Compare commits
523 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b52270ff25 | |||
| c0aa9acb19 | |||
| 89678aab1a | |||
| fa0afbfe18 | |||
| 9fe3a0be29 | |||
| c425543491 | |||
| 37270e8e65 | |||
| 299def8f02 | |||
| d0241e987f | |||
| 85ceb901bd | |||
| 3ffb60e78f | |||
| bca45371bc | |||
| 42be87dc37 | |||
| 84c253a9f6 | |||
| 827fb257ab | |||
| 10f24b60d6 | |||
| 279173cee8 | |||
| 50a4aad871 | |||
| dc4b2ec8ca | |||
| 2add68b33a | |||
| 9a5384e3ef | |||
| 5adac967a0 | |||
| 4211f27d88 | |||
| 3c72ca7175 | |||
| 5e2862926a | |||
| 49b3085ab1 | |||
| b74426a40c | |||
| 91e986e613 | |||
| b25987c865 | |||
| aa9d25d4ee | |||
| fa562b9487 | |||
| 66ef753b67 | |||
| c29362be7c | |||
| d209804005 | |||
| 63b3f5df26 | |||
| 93a3a06963 | |||
| 5cb7fb73c6 | |||
| 6a9114fd9a | |||
| b3fd42d076 | |||
| ea13b67364 | |||
| 6b9195476a | |||
| 396248e41e | |||
| d30df26cc8 | |||
| 5ed5ee5ca9 | |||
| a0354a9d94 | |||
| a7c3acce27 | |||
| 646ed19ded | |||
| 06e2b8a380 | |||
| 6cd9377866 | |||
| 781ebe1704 | |||
| 345d02e310 | |||
| ce067c67d1 | |||
| 9c3c1cfd82 | |||
| 9c2a349242 | |||
| 575c728bdc | |||
| 67cf863c38 | |||
| 20a8b32cdf | |||
| 837f597342 | |||
| 7f129b2107 | |||
| 21d79dec0b | |||
| 6d98bcb9b2 | |||
| 41ac60fd17 | |||
| aecf830211 | |||
| b32a751231 | |||
| 26fc76caa0 | |||
| 9b4f5d59dc | |||
| 4a607a5687 | |||
| 28a484ee42 | |||
| 5fdd35c4d5 | |||
| cf39ea4ad6 | |||
| 07e077cba0 | |||
| 3b51cc83ca | |||
| 0d5bad7186 | |||
| 797cb94716 | |||
| bfa5e350f8 | |||
| 7f4e4c9757 | |||
| 483dd6bc79 | |||
| 62fb7a2278 | |||
| 1406a76b6b | |||
| bf822fe449 | |||
| 6ec1b8c202 | |||
| 1cfdbd3e5d | |||
| 4711a999f0 | |||
| 529ae9c40c | |||
| 58797cb20f | |||
| 0360a9664c | |||
| 12f8bc338e | |||
| a8b326437c | |||
| 4b04a53578 | |||
| c30f82e468 | |||
| 0aa6f7ac5a | |||
| b3f22240b0 | |||
| cd26b26d1d | |||
| c392460dd7 | |||
| 1690fa4d44 | |||
| f433cff03d | |||
| e5e2c2ea74 | |||
| 2c46a752f9 | |||
| 0b29e15af6 | |||
| 08e6f5c29f | |||
| a81dd74257 | |||
| db5fa33f61 | |||
| ee907ce498 | |||
| 676f0ce1e6 | |||
| 4850748c77 | |||
| 5aa6291ae3 | |||
| baeb3a5521 | |||
| 513690e9a3 | |||
| 754998830c | |||
| 00444a4c0d | |||
| e61ded6ef5 | |||
| 5ce21ec2f5 | |||
| 94ff383a86 | |||
| 2c21e5c2fe | |||
| 69473a349e | |||
| f3e90725cc | |||
| a99c50a116 | |||
| 714745f649 | |||
| 1928ddd350 | |||
| dcc13945a2 | |||
| 33aec3582e | |||
| 5f9c08984c | |||
| cee99fc39e | |||
| 2e0efd6044 | |||
| cb2fd761a3 | |||
| dfa3ab413b | |||
| c541ecb96d | |||
| 7da1e91f5e | |||
| a46e66c022 | |||
| e86464c3c2 | |||
| 28e519d937 | |||
| 9bd463cbd1 | |||
| 29f821f026 | |||
| 0fbb08ed58 | |||
| c062a8f6a3 | |||
| 8d4dd1bda9 | |||
| 2004391c9b | |||
| 0b1be47fb6 | |||
| 221183e196 | |||
| 9f218a59a2 | |||
| a9ad66dc2e | |||
| 6ea25f35a4 | |||
| d093dd7f57 | |||
| 460818a50a | |||
| 8fa9d7235f | |||
| 95915678c3 | |||
| c22d7a36a0 | |||
| f641cb9b82 | |||
| 74ebcbe630 | |||
| 5b27d5c07e | |||
| 37bbb14fdb | |||
| 13cc75765b | |||
| fff3211e61 | |||
| a1c0da9688 | |||
| 3c933d8e4f | |||
| 2ddfdc1db4 | |||
| 1f986439b2 | |||
| d7fd23800b | |||
| 0f1a55462e | |||
| 3016bb54f1 | |||
| 93fa562e2d | |||
| e7c4ba752b | |||
| 7f7ed83bba | |||
| e4b28f7679 | |||
| 7ff9c2b78e | |||
| 97e1ab470a | |||
| a0b13362de | |||
| a3f2168f3a | |||
| 84fa24e194 | |||
| b2066bfad7 | |||
| be6953b83f | |||
| c9eab465ea | |||
| e451efad4f | |||
| 50b57d1fac | |||
| b8cc600ae6 | |||
| af284dbe4b | |||
| 88c2c430c6 | |||
| e3d990077d | |||
| 00b6d28196 | |||
| a0cd1182c1 | |||
| ac2f2654a3 | |||
| 3b92bdb3ea | |||
| 6d47eb377d | |||
| a475e3a396 | |||
| b782fae562 | |||
| 289ffee605 | |||
| b29e8eb893 | |||
| 5f53ab9d7d | |||
| 3bfa88b4d8 | |||
| ae48aca021 | |||
| e307494a53 | |||
| a660e1c08e | |||
| 656038dc7d | |||
| 641144bd66 | |||
| 9389386030 | |||
| 4eb7e6142b | |||
| fef9f27c2d | |||
| 989ec6ed03 | |||
| 12f61a5bb5 | |||
| 3aab5da74f | |||
| 11c21f01a2 | |||
| 46baac8bbd | |||
| cdd8644419 | |||
| becf0bf249 | |||
| a10d597e7e | |||
| 12ab8b5f88 | |||
| c825fd0d94 | |||
| e62d83b62b | |||
| 1c3ef9b361 | |||
| 7a2ffac535 | |||
| 87e91ad850 | |||
| 21de24af6a | |||
| df76dcaa54 | |||
| b7bcdc2096 | |||
| 99b01b7f78 | |||
| a5b473956d | |||
| 4e7ef150a3 | |||
| 00ee4651b9 | |||
| fab3779116 | |||
| b0bebb81ca | |||
| b4d6c66ed3 | |||
| 133e63a96f | |||
| 49ecd46ef3 | |||
| 02df2c7432 | |||
| 4b09fbdadd | |||
| 2d190b5103 | |||
| eb931b5fd4 | |||
| 419dfb6e0b | |||
| 417b8b3927 | |||
| 1f145e9d24 | |||
| 03b43ba4ac | |||
| c1c3ab71ba | |||
| d8863f79a7 | |||
| 5d2ffd3aa6 | |||
| ebc46f6323 | |||
| 8f925a1e6c | |||
| cf0376d5e1 | |||
| 77dd313b12 | |||
| bc98a865af | |||
| 0c2a419d0b | |||
| 68e225c3b4 | |||
| 05c1a159c1 | |||
| ebe679914d | |||
| fb84e7cebd | |||
| c9637f2dd3 | |||
| ac588a6f6f | |||
| 7d574e9172 | |||
| 709e35f4dc | |||
| 00efca071f | |||
| d1cd8b0d5c | |||
| 9b331798fb | |||
| fb851bbfc1 | |||
| dcf4de9900 | |||
| 4afa0064e9 | |||
| eb880adf57 | |||
| b4e9e204bc | |||
| 437e52896e | |||
| 8d27725583 | |||
| 314bc98044 | |||
| 93804a751a | |||
| 779c13f25a | |||
| a659375e1f | |||
| 0fa38df2c9 | |||
| d7060dd82e | |||
| fdbf891fad | |||
| 8cfcb18d6a | |||
| 8f1d367484 | |||
| bb41e1052f | |||
| 592015e3ee | |||
| 00f934c0d5 | |||
| 86e3ac485c | |||
| adffcf1852 | |||
| da361fcca2 | |||
| 17fd230ebb | |||
| d83f061a1c | |||
| 4f341594b5 | |||
| a9472ff0a3 | |||
| b7229f32f8 | |||
| 4a4bf7b5cb | |||
| eef386d6c8 | |||
| 5bfe8401f5 | |||
| 268f8665d0 | |||
| ceefabb8e4 | |||
| 81c8f8f50e | |||
| 090f51f624 | |||
| 0b179f9739 | |||
| af60e61c5c | |||
| 5d9014acc3 | |||
| 9d5ab6e80e | |||
| 52624c4542 | |||
| 5d0c019bd5 | |||
| 7824a7cc7a | |||
| 45aa4c5d92 | |||
| 6898e544f7 | |||
| 3dd5311430 | |||
| 8d8033027d | |||
| d8eae58bfd | |||
| 530f2ea98d | |||
| 6039ca70c5 | |||
| bc2275300d | |||
| 6485b8ca22 | |||
| dbc7cc2dfa | |||
| d960f518be | |||
| eda1955956 | |||
| 354013fa41 | |||
| f63f480e57 | |||
| c2daafed59 | |||
| 64dbdf57c1 | |||
| 8e7832912d | |||
| e0795595e7 | |||
| f5e7fcf51f | |||
| 98fae744c0 | |||
| d909aa4c4e | |||
| d520b5fbc4 | |||
| 2ce699faa7 | |||
| 709e40fc28 | |||
| 15214aa07e | |||
| 9bf6d000ed | |||
| 9b873479ac | |||
| e45fbef80a | |||
| ca24cb9e58 | |||
| 92024adb53 | |||
| 6a3aa12f1d | |||
| 24322a411a | |||
| 623f0362fd | |||
| 4ea5945101 | |||
| 4b5d9b6486 | |||
| 7e02cc582c | |||
| 14080f7e30 | |||
| b764ced6fa | |||
| 85d19dcccf | |||
| ac6c9af6d9 | |||
| 6a6f14b7a3 | |||
| 6e21c3b5ab | |||
| 843abbeaa6 | |||
| 7e409968be | |||
| 211905278b | |||
| d80d4af8c5 | |||
| a03d076299 | |||
| 150cdbbbfa | |||
| cd509b2663 | |||
| 0705eefd69 | |||
| d2c42c8553 | |||
| a55944a285 | |||
| cba75d419d | |||
| f77374519e | |||
| 52c6ee7053 | |||
| 3c3e7f900b | |||
| e39a63523e | |||
| 983722d22f | |||
| e54ac1ed39 | |||
| 912738ae1c | |||
| d48d0d81c7 | |||
| 838847bd78 | |||
| d50f99e144 | |||
| 7c26dff45e | |||
| dfe62ef592 | |||
| d2dd255c90 | |||
| 93ae880902 | |||
| 7077095f7a | |||
| b2dfedfe63 | |||
| 0b70d9109c | |||
| f729233ffd | |||
| 8deff8743a | |||
| 71c1d8c9d3 | |||
| 8630d79519 | |||
| f595f1146e | |||
| 77087baed9 | |||
| 5c91717d84 | |||
| 60003c4527 | |||
| 38f00206eb | |||
| f139f32c85 | |||
| f20e695919 | |||
| 4a7d4165f8 | |||
| b515f04c97 | |||
| 287dc99362 | |||
| 824dd399db | |||
| 4419b7b237 | |||
| 3e609a48ef | |||
| 85277cd277 | |||
| 4927294b9e | |||
| 0535d6fd7f | |||
| 92b5b248a3 | |||
| 0a70a95b63 | |||
| a79a469547 | |||
| 4daad7d111 | |||
| 10de6b5246 | |||
| d1b870a8ca | |||
| 1955e73881 | |||
| 8b7dc42185 | |||
| 751168b2de | |||
| 8681a23919 | |||
| 80fd889ae4 | |||
| def499c2f6 | |||
| ab2ec0f790 | |||
| ffc9b57cad | |||
| 734db55904 | |||
| 864c8fa84c | |||
| 4f5c63e222 | |||
| bab0512dd6 | |||
| 4af173deff | |||
| 9cd44aad3d | |||
| 4f5fba5ce4 | |||
| 66dc6de141 | |||
| c3e914ecf1 | |||
| 7232269ad0 | |||
| b601c4150b | |||
| 54e1ecd10f | |||
| 9c7d284e17 | |||
| b1b22bf835 | |||
| 35239ed0dc | |||
| a89061c90c | |||
| 1570239840 | |||
| 875cbe08db | |||
| 0b9d570871 | |||
| a465d2f489 | |||
| 6e7fe74130 | |||
| eab01dee1b | |||
| 7ac19eb76b | |||
| 5ee6a6ab54 | |||
| 1c5279f7c7 | |||
| aa598cfb4f | |||
| 2b1f5f3804 | |||
| b7fe54451c | |||
| e01a1cbb7b | |||
| 66a76c3fb1 | |||
| 69138a56e2 | |||
| 6bc1b9238e | |||
| 215b3ced71 | |||
| 696db2ec66 | |||
| 99250b3e03 | |||
| adcabf4df6 | |||
| 635372cd83 | |||
| 513f947b28 | |||
| c032120de0 | |||
| 632fe7569e | |||
| bbd960899a | |||
| 37784a238a | |||
| 360347325e | |||
| d67bbd69ca | |||
| 56c4f42b97 | |||
| c0efa2f913 | |||
| a71924dd37 | |||
| ecddacb321 | |||
| 70271e3db4 | |||
| 7fd29e4982 | |||
| b551e5e22c | |||
| a0d62fdc01 | |||
| 867f76e058 | |||
| 457ae27528 | |||
| dbfad195e3 | |||
| d5293f28b7 | |||
| f59e2870c0 | |||
| 698b0ad0ff | |||
| 8e4f345091 | |||
| 70a5a5ea59 | |||
| 689f1cc32a | |||
| 09dd2443c7 | |||
| 1cdb8aceac | |||
| 8bb593bf3e | |||
| 3bc08ec6d0 | |||
| 01694d39ae | |||
| 58f1eeb91c | |||
| a0920dfb92 | |||
| 02c879442c | |||
| 99c824c467 | |||
| fa66eef192 | |||
| 7564a8229f | |||
| 6dd4a036b0 | |||
| f479f037f7 | |||
| c59c564f32 | |||
| 7a331e36ad | |||
| 2e073ddbb2 | |||
| 064ca3f728 | |||
| 634b9223e0 | |||
| 7a6de074b9 | |||
| eba7dc29b3 | |||
| 4887fb036c | |||
| a5bb77a0ec | |||
| 59f3322635 | |||
| 2f540211c9 | |||
| fcbdda6239 | |||
| dca19bf88b | |||
| 04dabe755e | |||
| 3675a592c4 | |||
| 2d0f214a9f | |||
| 8cd3886494 | |||
| a75561a415 | |||
| 106e84914d | |||
| 4f54e5bdf8 | |||
| 79ac0bd558 | |||
| d36a359cc0 | |||
| a36817e89c | |||
| 5b93689184 | |||
| fce7551dc3 | |||
| 826dcb58e5 | |||
| 244ed0fded | |||
| 60e891b08c | |||
| f42614ea5d | |||
| a70c66cc99 | |||
| c9a904f065 | |||
| 69a7735144 | |||
| 7b283e1c19 | |||
| 97a5b58d11 | |||
| ca274a3910 | |||
| 4d6f7d1d13 | |||
| 8296cda1f2 | |||
| 3bb14c5acb | |||
| b5bfff66dd | |||
| adb2269df0 | |||
| b557f15a98 | |||
| 862acf1db1 | |||
| a2272edc76 | |||
| 555d653288 | |||
| 45cf88e52c | |||
| a8f840bfb2 | |||
| d8222366b1 | |||
| fbe13eaa7e | |||
| 466df3387f | |||
| fa76b5170a | |||
| b0c66c9c6a | |||
| 2ffdf83645 | |||
| c3a3551ba3 |
@@ -33,5 +33,4 @@ runtime/
|
||||
|
||||
oot
|
||||
d
|
||||
|
||||
composer.lock
|
||||
|
||||
+6
-2
@@ -5,14 +5,18 @@ namespace PHPSTORM_META {
|
||||
// Reflect
|
||||
use Kiri\Di\Container;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Container\ContainerInterface as SC;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
override(ContainerInterface::get(0), map('@'));
|
||||
override(ContainerInterface::get(0), map('@'));
|
||||
override(SC::get(0), map('@'));
|
||||
override(Container::get(0), map('@'));
|
||||
override(Container::make(0), map('@'));
|
||||
override(Container::create(0), map('@'));
|
||||
// override(\Hyperf\Utils\Context::get(0), map('@'));
|
||||
// override(\make(0), map('@'));
|
||||
override(\make(0), map('@'));
|
||||
override(\di(0), map('@'));
|
||||
override(\duplicate(0), map('@'));
|
||||
override(ServerRequestInterface::getAttribute(0), map('@'));
|
||||
|
||||
}
|
||||
|
||||
@@ -5,27 +5,19 @@ declare(strict_types=1);
|
||||
error_reporting(0);
|
||||
|
||||
|
||||
use Database\Collection;
|
||||
use Database\ModelInterface;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Kiri\Abstracts\Config;
|
||||
use Kiri\Annotation\Annotation;
|
||||
use Kiri\Application;
|
||||
use Kiri\Core\Json;
|
||||
use Kiri\Di\Container;
|
||||
use Kiri\Environmental;
|
||||
use Kiri\Server\Tasker\AsyncTaskExecute;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Kiri\Error\StdoutLogger;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Process;
|
||||
use Swoole\WebSocket\Server;
|
||||
|
||||
defined('DB_ERROR_BUSY') or define('DB_ERROR_BUSY', 'The database is busy. Please try again later.');
|
||||
defined('SELECT_IS_NULL') or define('SELECT_IS_NULL', 'Query data does not exist, please check the relevant conditions.');
|
||||
defined('PARAMS_IS_NULL') or define('PARAMS_IS_NULL', 'Required items cannot be empty, please add.');
|
||||
defined('CONTROLLER_PATH') or define('CONTROLLER_PATH', realpath(APP_PATH . 'controllers/'));
|
||||
defined('MODEL_PATH') or define('MODEL_PATH', realpath(APP_PATH . 'models/'));
|
||||
defined('CONTROLLER_PATH') or define('CONTROLLER_PATH', realpath(APP_PATH . 'app/Controller/'));
|
||||
defined('MODEL_PATH') or define('MODEL_PATH', realpath(APP_PATH . 'app/Model/'));
|
||||
defined('COMPONENT_PATH') or define('COMPONENT_PATH', realpath(APP_PATH . 'components/'));
|
||||
defined('URL_MATCH') or define('URL_MATCH', '/(http[s]?:\/\/)?((?:[\w\-_]+\.)+\w+(?::\d+)?)(?:(\/[a-zA-Z0-9-\/]+)+[\/]?(\?[a-zA-Z]+=.*)?)?/');
|
||||
|
||||
|
||||
/**
|
||||
@@ -35,603 +27,253 @@ defined('COMPONENT_PATH') or define('COMPONENT_PATH', realpath(APP_PATH . 'compo
|
||||
class Kiri
|
||||
{
|
||||
|
||||
/** @var Container */
|
||||
private static Container $container;
|
||||
|
||||
|
||||
/** @var ?Application */
|
||||
private static ?Application $service = null;
|
||||
|
||||
|
||||
/**
|
||||
* @param $service
|
||||
*
|
||||
* 初始化服务
|
||||
*/
|
||||
public static function init($service)
|
||||
{
|
||||
static::$service = $service;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Container $container
|
||||
*/
|
||||
public static function setContainer(Container $container)
|
||||
{
|
||||
$container->setBindings(ContainerInterface::class, $container);
|
||||
static::$container = $container;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Container
|
||||
*/
|
||||
public static function getContainer(): Container
|
||||
{
|
||||
return static::$container;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $alias
|
||||
* @param array $array
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function set($alias, array $array = [])
|
||||
{
|
||||
static::app()->set($alias, $array);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getApp(string $name): mixed
|
||||
{
|
||||
return static::app()->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Application|null
|
||||
*/
|
||||
public static function app(): ?Application
|
||||
{
|
||||
return static::$service;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Application|null
|
||||
*/
|
||||
public static function getFactory(): ?Application
|
||||
{
|
||||
return static::$service;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Application|null
|
||||
*/
|
||||
public static function getApplicationContext(): ?Application
|
||||
{
|
||||
return static::$service;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Container|null
|
||||
*/
|
||||
public static function getContainerContext(): ?Container
|
||||
{
|
||||
return static::$container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return bool
|
||||
*/
|
||||
public static function has($name): bool
|
||||
{
|
||||
return static::$service->has($name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $port
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function port_already($port): bool
|
||||
{
|
||||
if (empty($port)) {
|
||||
return false;
|
||||
}
|
||||
if (Kiri::getPlatform()->isLinux()) {
|
||||
exec('netstat -tunlp | grep ' . $port, $output);
|
||||
} else {
|
||||
exec('lsof -i :' . $port . ' | grep -i "LISTEN"', $output);
|
||||
}
|
||||
return !empty($output);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Annotation
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getAnnotation(): Annotation
|
||||
{
|
||||
return static::app()->getAnnotation();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $service
|
||||
* @return string
|
||||
*/
|
||||
#[Pure] public static function listen($service): string
|
||||
{
|
||||
return sprintf('Check listen %s::%d -> ok', $service['host'], $service['port']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $className
|
||||
* @param array $construct
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function createObject($className, array $construct = []): mixed
|
||||
{
|
||||
if (is_string($className) && class_exists($className)) {
|
||||
return static::$container->get($className, $construct);
|
||||
} else if (is_array($className) && isset($className['class'])) {
|
||||
$class = $className['class'];
|
||||
unset($className['class']);
|
||||
return static::$container->create($class, $construct, $className);
|
||||
} else if (is_callable($className, TRUE)) {
|
||||
return call_user_func($className, $construct);
|
||||
} else {
|
||||
throw new Exception('Unsupported configuration type: ' . gettype($className));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getStoragePath(): string
|
||||
{
|
||||
$default = APP_PATH . 'storage' . DIRECTORY_SEPARATOR;
|
||||
$path = Config::get('storage', $default);
|
||||
if (!is_dir($path)) {
|
||||
mkdir($path, 0777, true);
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function inCoroutine(): bool
|
||||
{
|
||||
return Coroutine::getCid() > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Container
|
||||
*/
|
||||
public static function getDi(): Container
|
||||
{
|
||||
return static::$container;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Container
|
||||
*/
|
||||
public static function di(): Container
|
||||
{
|
||||
return static::$container;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $workerId
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function setManagerId($workerId): mixed
|
||||
{
|
||||
if (empty($workerId) || static::isDocker()) {
|
||||
return $workerId;
|
||||
}
|
||||
|
||||
$tmpFile = storage($workerId . '.sock', 'pid/manager');
|
||||
|
||||
return self::writeFile($tmpFile, $workerId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $workerId
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function setProcessId($workerId): mixed
|
||||
{
|
||||
if (empty($workerId) || static::isDocker()) {
|
||||
return $workerId;
|
||||
}
|
||||
|
||||
$tmpFile = storage($workerId . '.sock', 'pid/process');
|
||||
|
||||
return self::writeFile($tmpFile, $workerId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isDocker(): bool
|
||||
{
|
||||
$output = shell_exec('[ -f /.dockerenv ] && echo yes || echo no');
|
||||
if (trim($output) === 'yes') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $workerId
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function setWorkerId($workerId): mixed
|
||||
{
|
||||
if (empty($workerId) || static::isDocker()) {
|
||||
return $workerId;
|
||||
}
|
||||
|
||||
$tmpFile = storage($workerId . '.sock', 'pid/worker');
|
||||
|
||||
return self::writeFile($tmpFile, $workerId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $workerId
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function setTaskId($workerId): mixed
|
||||
{
|
||||
if (empty($workerId) || static::isDocker()) {
|
||||
return $workerId;
|
||||
}
|
||||
|
||||
$tmpFile = storage($workerId . '.sock', 'pid/task');
|
||||
|
||||
return self::writeFile($tmpFile, $workerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fileName
|
||||
* @param $content
|
||||
* @param null $is_append
|
||||
* @return mixed
|
||||
*/
|
||||
public static function writeFile($fileName, $content, $is_append = null): mixed
|
||||
{
|
||||
$params = [$fileName, (string)$content];
|
||||
if ($is_append !== null) {
|
||||
$params[] = $is_append;
|
||||
}
|
||||
return !self::inCoroutine() ? file_put_contents(...$params) : Coroutine::writeFile(...$params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $object
|
||||
* @param $config
|
||||
* @return mixed
|
||||
*/
|
||||
public static function configure($object, $config): mixed
|
||||
{
|
||||
foreach ($config as $key => $value) {
|
||||
if (!property_exists($object, $key)) {
|
||||
continue;
|
||||
}
|
||||
$object->$key = $value;
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $workerId
|
||||
* @param bool $isWorker
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function clearProcessId($workerId, bool $isWorker = false)
|
||||
{
|
||||
clearstatcache();
|
||||
$directory = $isWorker === true ? 'pid/worker' : 'pid/task';
|
||||
if (!file_exists($file = storage($workerId, $directory))) {
|
||||
return;
|
||||
}
|
||||
shell_exec('rm -rf ' . $file);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string|null $taskPid
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function clearTaskPid(string $taskPid = null)
|
||||
{
|
||||
if (empty($taskPid)) {
|
||||
exec('rm -rf ' . storage(null, 'pid/task'));
|
||||
} else {
|
||||
static::clearProcessId($taskPid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $taskPid
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function clearWorkerPid($taskPid = null)
|
||||
{
|
||||
if (empty($taskPid)) {
|
||||
exec('rm -rf ' . storage(null, 'pid/worker'));
|
||||
} else {
|
||||
static::clearProcessId($taskPid, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Server|null
|
||||
* @throws
|
||||
*/
|
||||
public static function getWebSocket(): ?\Swoole\Server
|
||||
{
|
||||
$server = static::app()->getSwoole();
|
||||
if (!($server instanceof \Swoole\Server)) {
|
||||
return null;
|
||||
}
|
||||
return $server;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return false|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getMasterPid(): bool|string
|
||||
{
|
||||
$pid = Kiri::app()->getSwoole()->setting['pid_file'];
|
||||
|
||||
return file_get_contents($pid);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $fd
|
||||
* @param $data
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function push(int $fd, $data): mixed
|
||||
{
|
||||
$server = static::getWebSocket();
|
||||
if (empty($server) || !$server->isEstablished($fd)) {
|
||||
return false;
|
||||
}
|
||||
if (!is_string($data)) {
|
||||
$data = Json::encode($data);
|
||||
}
|
||||
return $server->push($fd, $data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public static function localhost(): mixed
|
||||
{
|
||||
return current(swoole_get_local_ip());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param array $params
|
||||
* @throws ReflectionException
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function async(string $class, array $params = [])
|
||||
{
|
||||
$manager = di(AsyncTaskExecute::class);
|
||||
$manager->execute(new $class(...$params));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $v1
|
||||
* @param array $v2
|
||||
* @return float
|
||||
*/
|
||||
#[Pure] public static function distance(array $v1, array $v2): float
|
||||
{
|
||||
$maxX = max($v1['x'], $v2['x']);
|
||||
$minX = min($v1['x'], $v2['x']);
|
||||
|
||||
$maxZ = max($v1['z'], $v2['z']);
|
||||
$minZ = min($v1['z'], $v2['z']);
|
||||
|
||||
$dx = abs($maxX - $minX);
|
||||
$dy = abs($maxZ - $minZ);
|
||||
|
||||
$sqrt = sqrt($dx * $dx + $dy * $dy);
|
||||
if ($sqrt < 0) {
|
||||
$sqrt = abs($sqrt);
|
||||
}
|
||||
return (float)$sqrt;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $process
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function shutdown($process): void
|
||||
{
|
||||
static::app()->getSwoole()->shutdown();
|
||||
if ($process instanceof Process) {
|
||||
$process->exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $tmp_name
|
||||
* @return string
|
||||
*/
|
||||
public static function rename($tmp_name): string
|
||||
{
|
||||
$hash = md5_file($tmp_name);
|
||||
|
||||
$later = '.' . exif_imagetype($tmp_name);
|
||||
|
||||
$match = '/(\w{12})(\w{5})(\w{9})(\w{6})/';
|
||||
$tmp = preg_replace($match, '$1-$2-$3-$4', $hash);
|
||||
|
||||
return strtoupper($tmp) . $later;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Environmental
|
||||
* @throws
|
||||
*/
|
||||
public static function getPlatform(): Environmental
|
||||
{
|
||||
return Kiri::createObject(Environmental::class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function reload(): mixed
|
||||
{
|
||||
return Kiri::app()->getSwoole()->reload();
|
||||
}
|
||||
|
||||
|
||||
private static array $_autoload = [];
|
||||
|
||||
|
||||
const PROCESS = 'process';
|
||||
const TASK = 'task';
|
||||
const WORKER = 'worker';
|
||||
|
||||
|
||||
/**
|
||||
* @param string $event
|
||||
* @param null $data
|
||||
* @return false|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function param(string $event, $data = NULL): bool|string
|
||||
{
|
||||
if (is_object($data)) {
|
||||
if ($data instanceof ModelInterface || $data instanceof Collection) {
|
||||
$data = $data->getAttributes();
|
||||
} else {
|
||||
$data = get_object_vars($data);
|
||||
}
|
||||
}
|
||||
if (!is_array($data)) $data = ['data' => $data];
|
||||
return json_encode(array_merge(['callback' => $event], $data));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
#[Pure] public static function getEnvironmental(): ?string
|
||||
{
|
||||
return env('environmental');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
#[Pure] public static function isTask(): bool
|
||||
{
|
||||
return static::getEnvironmental() == static::TASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
#[Pure] public static function isWorker(): bool
|
||||
{
|
||||
return static::getEnvironmental() == static::WORKER;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
#[Pure] public static function isProcess(): bool
|
||||
{
|
||||
return static::getEnvironmental() == static::PROCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $file
|
||||
*/
|
||||
public static function setAutoload($class, $file)
|
||||
{
|
||||
if (isset(static::$_autoload[$class])) {
|
||||
return;
|
||||
}
|
||||
static::$_autoload[$class] = $file;
|
||||
include_once "Kiri.php";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $className
|
||||
*/
|
||||
public static function autoload($className)
|
||||
{
|
||||
if (!isset(static::$_autoload[$className])) {
|
||||
return;
|
||||
}
|
||||
$file = static::$_autoload[$className];
|
||||
require_once "Kiri.php";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Container
|
||||
*/
|
||||
public static function getContainer(): Container
|
||||
{
|
||||
return Container::instance();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Container|null
|
||||
*/
|
||||
public static function getContainerContext(): ?Container
|
||||
{
|
||||
return static::getContainer();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string|array $className
|
||||
* @param array $construct
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public static function createObject(string|array $className, array $construct = []): mixed
|
||||
{
|
||||
$container = static::getContainer();
|
||||
if (is_string($className) && class_exists($className)) {
|
||||
$object = $container->get($className);
|
||||
return self::configure($object, $construct);
|
||||
} else if (is_array($className) && isset($className['class'])) {
|
||||
$class = $className['class'];
|
||||
unset($className['class']);
|
||||
return $container->make($class, $construct, $className);
|
||||
} else if (is_callable($className, TRUE)) {
|
||||
return call_user_func($className, $construct);
|
||||
} else {
|
||||
throw new Exception('Unsupported configuration type: ' . gettype($className));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \Kiri\Pool\Pool
|
||||
* @throws
|
||||
*/
|
||||
public static function getPool(): \Kiri\Pool\Pool
|
||||
{
|
||||
return static::getDi()->get(\Kiri\Pool\Pool::class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $prefix
|
||||
* @return void
|
||||
*/
|
||||
public static function setProcessName($prefix): void
|
||||
{
|
||||
if (Kiri::getPlatform()->isMac()) {
|
||||
return;
|
||||
}
|
||||
$name = '[' . \config('id', 'system-service') . ']';
|
||||
if (!empty($prefix)) {
|
||||
$name .= '.' . $prefix;
|
||||
}
|
||||
swoole_set_process_name($name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws
|
||||
*/
|
||||
public static function getStoragePath(): string
|
||||
{
|
||||
$default = APP_PATH . 'storage' . DIRECTORY_SEPARATOR;
|
||||
$path = \config('storage', $default);
|
||||
if (!is_dir($path)) {
|
||||
mkdir($path, 0777, true);
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Container
|
||||
*/
|
||||
public static function getDi(): Container
|
||||
{
|
||||
return static::getContainer();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return StdoutLogger
|
||||
* @throws
|
||||
*/
|
||||
public static function getLogger(): StdoutLogger
|
||||
{
|
||||
return static::getContainer()->get(StdoutLogger::class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isDocker(): bool
|
||||
{
|
||||
$output = shell_exec('[ -f /.dockerenv ] && echo yes || echo no');
|
||||
if (trim($output) === 'yes') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $fileName
|
||||
* @param $content
|
||||
* @param null $is_append
|
||||
* @return int|bool
|
||||
*/
|
||||
public static function writeFile($fileName, $content, $is_append = null): int|bool
|
||||
{
|
||||
$params = [$fileName, (string)$content];
|
||||
if ($is_append !== null) {
|
||||
$params[] = $is_append;
|
||||
}
|
||||
return !(Coroutine::getCid() > 0) ? file_put_contents(...$params) : Coroutine::writeFile(...$params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $object
|
||||
* @param $config
|
||||
* @return mixed
|
||||
*/
|
||||
public static function configure($object, $config): mixed
|
||||
{
|
||||
foreach ($config as $key => $value) {
|
||||
if (!property_exists($object, $key)) {
|
||||
continue;
|
||||
}
|
||||
$object->$key = $value;
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public static function localhost(): mixed
|
||||
{
|
||||
return current(swoole_get_local_ip());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $v1
|
||||
* @param array $v2
|
||||
* @return float
|
||||
*/
|
||||
#[Pure] public static function distance(array $v1, array $v2): float
|
||||
{
|
||||
$maxX = max($v1['x'], $v2['x']);
|
||||
$minX = min($v1['x'], $v2['x']);
|
||||
|
||||
$maxZ = max($v1['z'], $v2['z']);
|
||||
$minZ = min($v1['z'], $v2['z']);
|
||||
|
||||
$dx = abs($maxX - $minX);
|
||||
$dy = abs($maxZ - $minZ);
|
||||
|
||||
$sqrt = sqrt($dx * $dx + $dy * $dy);
|
||||
if ($sqrt < 0) {
|
||||
$sqrt = abs($sqrt);
|
||||
}
|
||||
return (float)$sqrt;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $tmp_name
|
||||
* @return string
|
||||
*/
|
||||
public static function rename($tmp_name): string
|
||||
{
|
||||
$hash = md5_file($tmp_name);
|
||||
|
||||
$later = '.' . exif_imagetype($tmp_name);
|
||||
|
||||
$match = '/(\w{12})(\w{5})(\w{9})(\w{6})/';
|
||||
$tmp = preg_replace($match, '$1-$2-$3-$4', $hash);
|
||||
|
||||
return strtoupper($tmp) . $later;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Environmental
|
||||
* @throws
|
||||
*/
|
||||
public static function getPlatform(): Environmental
|
||||
{
|
||||
return Kiri::createObject(Environmental::class);
|
||||
}
|
||||
|
||||
|
||||
const PROCESS = 'process';
|
||||
const TASK = 'task';
|
||||
const WORKER = 'worker';
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
#[Pure] public static function getEnvironmental(): ?string
|
||||
{
|
||||
return env('environmental');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
#[Pure] public static function isTask(): bool
|
||||
{
|
||||
return static::getEnvironmental() == static::TASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
#[Pure] public static function isWorker(): bool
|
||||
{
|
||||
return static::getEnvironmental() == static::WORKER;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
#[Pure] public static function isProcess(): bool
|
||||
{
|
||||
return static::getEnvironmental() == static::PROCESS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//spl_autoload_register([Kiri::class, 'autoload'], true, true);
|
||||
Kiri::setContainer(new Container());
|
||||
|
||||
+22
-10
@@ -9,7 +9,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"php": ">=8.3",
|
||||
"ext-json": "*",
|
||||
"ext-fileinfo": "*",
|
||||
"ext-pdo": "*",
|
||||
@@ -21,26 +21,38 @@
|
||||
"ext-xml": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-openssl": "*",
|
||||
"ext-swoole": "*",
|
||||
"ext-msgpack": "*",
|
||||
"symfony/console": "~v5.3.10",
|
||||
"psr/log": "1.*",
|
||||
"composer-runtime-api": "^2.0",
|
||||
"psr/container": "^2.0",
|
||||
"psr/http-server-middleware": "1.0.1",
|
||||
"game-worker/kiri-event": "~v2.0",
|
||||
"ext-inotify": "*"
|
||||
"ext-pcntl": "*",
|
||||
"ext-sockets": "*",
|
||||
"nikic/php-parser": "^4.15",
|
||||
"ext-inotify": "*",
|
||||
"game-worker/kiri-pool": "~v1.0",
|
||||
"monolog/monolog": "^2.9",
|
||||
"psr/container": "^2.0",
|
||||
"ext-libsodium": "*",
|
||||
"swiftmailer/swiftmailer": "^6.3"
|
||||
},
|
||||
"replace": {
|
||||
"symfony/polyfill-apcu": "*",
|
||||
"symfony/polyfill-php80": "*",
|
||||
"symfony/polyfill-mbstring": "*",
|
||||
"symfony/polyfill-ctype": "*",
|
||||
"symfony/polyfill-php73": "*",
|
||||
"symfony/polyfill-php72": "*",
|
||||
"symfony/polyfill-php81": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Kiri\\": "kiri-engine/",
|
||||
"Kiri\\Gateway\\": "kiri-gateway/",
|
||||
"Kiri\\Websocket\\": "kiri-websocket-server/",
|
||||
"Gii\\": "kiri-gii/",
|
||||
"Kiri\\Annotation\\": "kiri-annotation/",
|
||||
"Kiri\\Task\\": "kiri-task/"
|
||||
"Kiri\\Actor\\": "kiri-actor/"
|
||||
},
|
||||
"files": [
|
||||
"Kiri.php",
|
||||
"error.php",
|
||||
"function.php"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
define('SUCCESS', 0);
|
||||
define('NO_AUTH', 401);
|
||||
|
||||
define('ERROR_MESSAGES', [
|
||||
SUCCESS => 'ok',
|
||||
NO_AUTH => ''
|
||||
]);
|
||||
|
||||
if (!function_exists('message')) {
|
||||
|
||||
/**
|
||||
* @param $code
|
||||
* @param $replace
|
||||
* @param string $default
|
||||
* @return mixed|string
|
||||
*/
|
||||
function message($code, $replace, $default = '')
|
||||
{
|
||||
if (!isset(ERROR_MESSAGES[$code])) {
|
||||
if (!empty($default)) {
|
||||
return $default;
|
||||
}
|
||||
return 'unknown error';
|
||||
}
|
||||
return sprintf(ERROR_MESSAGES[$code], $replace);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+799
-1054
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Actor;
|
||||
|
||||
use Exception;
|
||||
use JsonSerializable;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Coroutine\Channel;
|
||||
|
||||
|
||||
/**
|
||||
* @Actor
|
||||
*/
|
||||
abstract class Actor implements ActorInterface, JsonSerializable
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @var Channel
|
||||
*/
|
||||
private Channel $channel;
|
||||
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private bool $isShutdown = false;
|
||||
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private int $messageId = -1;
|
||||
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private int $coroutineId = -1;
|
||||
|
||||
|
||||
/**
|
||||
* @var ActorState
|
||||
*/
|
||||
private ActorState $state;
|
||||
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
private float $startTime = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private int $refreshInterval = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @return ActorState
|
||||
*/
|
||||
public function getState(): ActorState
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ActorState $state
|
||||
*/
|
||||
public function setState(ActorState $state): void
|
||||
{
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getRunTime(): float
|
||||
{
|
||||
return microtime(true) - $this->startTime;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $uniqueId
|
||||
*/
|
||||
private function __construct(readonly public string $uniqueId)
|
||||
{
|
||||
$this->channel = new Channel(99);
|
||||
$this->startTime = microtime(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isShutdown(): bool
|
||||
{
|
||||
return $this->isShutdown;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return static
|
||||
*/
|
||||
public static function newActor($id): static
|
||||
{
|
||||
$actor = new static($id);
|
||||
$actor->listen();
|
||||
return $actor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private function listen(): void
|
||||
{
|
||||
Coroutine::create(function (Actor $actor) {
|
||||
$actor->coroutineId = Coroutine::getCid();
|
||||
$this->run();
|
||||
}, $this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->uniqueId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $response
|
||||
* @return bool
|
||||
*/
|
||||
public function write(mixed $response): bool
|
||||
{
|
||||
return $this->channel->push($response);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function shutdown(): void
|
||||
{
|
||||
$this->isShutdown = true;
|
||||
Coroutine::cancel($this->coroutineId);
|
||||
if ($this->messageId > -1) {
|
||||
Coroutine::cancel($this->messageId);
|
||||
}
|
||||
$this->channel->close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function onUpdate(): void
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
if ($this->refreshInterval < 1) {
|
||||
throw new Exception('Refresh interval must be greater than 1');
|
||||
}
|
||||
$this->setState(ActorState::BUSY);
|
||||
$this->init();
|
||||
$this->messageId = Coroutine::create(fn() => $this->loop());
|
||||
$this->interval();
|
||||
$this->setState(ActorState::IDLE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private function interval(): void
|
||||
{
|
||||
if ($this->isShutdown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->onUpdate();
|
||||
} catch (\Throwable $exception) {
|
||||
error($exception);
|
||||
}
|
||||
|
||||
Coroutine::sleep($this->refreshInterval / 1000);
|
||||
|
||||
$this->interval();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function loop(): bool
|
||||
{
|
||||
if ($this->messageId == -1) {
|
||||
$this->messageId = Coroutine::getCid();
|
||||
}
|
||||
if ($this->channel->errCode == SWOOLE_CHANNEL_CLOSED) {
|
||||
$this->channel = new Channel(99);
|
||||
}
|
||||
$message = $this->channel->pop();
|
||||
$this->process($message);
|
||||
if ($this->isShutdown()) {
|
||||
return true;
|
||||
}
|
||||
return $this->loop();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Actor;
|
||||
|
||||
interface ActorInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param ActorMessage $message
|
||||
* @return void
|
||||
*/
|
||||
public function process(ActorMessage $message): void;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Actor;
|
||||
|
||||
use Swoole\Coroutine;
|
||||
|
||||
class ActorManager
|
||||
{
|
||||
|
||||
/** @var array<string, ActorInterface> */
|
||||
private array $nodes = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param Actor $actor
|
||||
* @return void
|
||||
*/
|
||||
public function addActor(ActorInterface $actor): void
|
||||
{
|
||||
$this->nodes[$actor->uniqueId] = $actor;
|
||||
Coroutine::create(function (Actor $actor) {
|
||||
$actor->run();
|
||||
}, $actor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return void
|
||||
*/
|
||||
public function closeActor($name): void
|
||||
{
|
||||
$node = $this->nodes[$name] ?? null;
|
||||
if (is_null($node)) {
|
||||
return;
|
||||
}
|
||||
foreach ($node as $actor) {
|
||||
$actor->shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $message
|
||||
* @return bool
|
||||
*/
|
||||
public function write($name, $message): bool
|
||||
{
|
||||
$actor = $this->nodes[$name] ?? null;
|
||||
if (is_null($actor)) {
|
||||
return false;
|
||||
}
|
||||
return $actor->write($message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return array
|
||||
*/
|
||||
public function lists($name): array
|
||||
{
|
||||
$array = [];
|
||||
foreach ($this->nodes[$name] as $actor) {
|
||||
$array[] = [
|
||||
'id' => $actor->getName(),
|
||||
'state' => $actor->getState()->name,
|
||||
'runTime' => $actor->getRunTime()
|
||||
];
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $uniqueId
|
||||
* @return bool
|
||||
*/
|
||||
public function hasActor(string $uniqueId): bool
|
||||
{
|
||||
return isset($this->nodes[$uniqueId]) && $this->nodes[$uniqueId] instanceof ActorInterface;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array|null $data
|
||||
* @return void
|
||||
*/
|
||||
public static function exec(?array $data): void
|
||||
{
|
||||
if (is_null($data)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function clean(): void
|
||||
{
|
||||
foreach ($this->nodes as $actor) {
|
||||
$actor->shutdown();
|
||||
}
|
||||
$this->nodes = [];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Actor;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
|
||||
class ActorMessage implements \JsonSerializable
|
||||
{
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private int $userId;
|
||||
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $event;
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private array $body;
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
* @param string $event
|
||||
* @param array $body
|
||||
*/
|
||||
public function __construct(int $userId, string $event, array $body)
|
||||
{
|
||||
$this->userId = $userId;
|
||||
$this->event = $event;
|
||||
$this->body = $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getUserId(): int
|
||||
{
|
||||
return $this->userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEvent(): string
|
||||
{
|
||||
return $this->event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getBody(): array
|
||||
{
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[ArrayShape(['userId' => "int", 'event' => "string", 'body' => "array"])]
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'userId' => $this->userId,
|
||||
'event' => $this->event,
|
||||
'body' => $this->body
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Actor;
|
||||
|
||||
use Kiri\Server\Abstracts\BaseProcess;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Process;
|
||||
|
||||
class ActorProcess extends BaseProcess
|
||||
{
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $enable_coroutine = true;
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
// TODO: Change the autogenerated stub
|
||||
return '[' . \config('id', 'system-service') . '].Actor Manager';
|
||||
}
|
||||
|
||||
|
||||
public function process(?Process $process): void
|
||||
{
|
||||
// TODO: Implement process() method.
|
||||
while ($this->isStop() === false) {
|
||||
$read = $process->read();
|
||||
|
||||
ActorManager::exec(json_decode($read, true));
|
||||
|
||||
Coroutine::sleep(1000 / 120);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function onSigterm(): static
|
||||
{
|
||||
// TODO: Implement onSigterm() method.
|
||||
Coroutine::create(function () {
|
||||
$sign = Coroutine::waitSignal(SIGINT | SIGTERM);
|
||||
if ($sign) {
|
||||
$this->onShutdown(true);
|
||||
}
|
||||
});
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Actor;
|
||||
|
||||
enum ActorState
|
||||
{
|
||||
case IDLE;
|
||||
case BUSY;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
case CREATE;
|
||||
case MESSAGE;
|
||||
case SHUTDOWN;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Annotation;
|
||||
|
||||
|
||||
use DirectoryIterator;
|
||||
use Exception;
|
||||
use ReflectionException;
|
||||
use Kiri\Abstracts\Component;
|
||||
|
||||
/**
|
||||
* Class Annotation
|
||||
* @package Annotation
|
||||
*/
|
||||
class Annotation extends Component
|
||||
{
|
||||
|
||||
|
||||
private Loader $_loader;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
$this->_loader = new Loader();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Loader
|
||||
*/
|
||||
public function getLoader(): Loader
|
||||
{
|
||||
return $this->_loader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Loader $loader
|
||||
* @return Loader
|
||||
*/
|
||||
public function setLoader(Loader $loader): Loader
|
||||
{
|
||||
return $this->_loader = $loader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param object $class
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function injectProperty(object $class)
|
||||
{
|
||||
$this->_loader->injectProperty($class::class, $class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string $namespace
|
||||
* @param array $exclude
|
||||
* @return static
|
||||
* @throws Exception
|
||||
*/
|
||||
public function read(string $path, string $namespace = 'App', array $exclude = []): static
|
||||
{
|
||||
$this->_loader->_scanDir(new DirectoryIterator($path), $namespace, $exclude);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $dir
|
||||
* @param array $exclude
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function runtime(string $dir, array $exclude = []): array
|
||||
{
|
||||
return $this->_loader->loadByDirectory($dir, $exclude);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Annotation;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
defined('ASPECT_ERROR') or define('ASPECT_ERROR', 'Aspect annotation must implement ');
|
||||
|
||||
/**
|
||||
* Class Aspect
|
||||
* @package Annotation
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_METHOD)] class Aspect extends Attribute
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Aspect constructor.
|
||||
* @param string $aspect
|
||||
*/
|
||||
public function __construct(public string $aspect)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function execute(mixed $class, mixed $method = ''): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Annotation;
|
||||
|
||||
|
||||
/**
|
||||
* Class Attribute
|
||||
* @package Annotation
|
||||
*/
|
||||
abstract class Attribute implements IAnnotation
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param static $class
|
||||
* @param mixed|string $method
|
||||
* @return mixed
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function execute(mixed $class, mixed $method = ''): mixed
|
||||
{
|
||||
// TODO: Implement execute() method.
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Annotation;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri\Events\EventProvider;
|
||||
use Kiri;
|
||||
|
||||
|
||||
/**
|
||||
* Class Event
|
||||
* @package Annotation
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_METHOD)] class Event extends Attribute
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Event constructor.
|
||||
* @param string $name
|
||||
* @param array $params
|
||||
*/
|
||||
public function __construct(public string $name, public array $params = [])
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $class
|
||||
* @param mixed|null $method
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function execute(mixed $class, mixed $method = null): bool
|
||||
{
|
||||
$pro = Kiri::getDi()->get(EventProvider::class);
|
||||
if (is_string($class)) {
|
||||
$class = Kiri::getDi()->get($class);
|
||||
}
|
||||
$pro->on($this->name, [$class, $method]);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Annotation;
|
||||
|
||||
|
||||
|
||||
interface IAnnotation
|
||||
{
|
||||
|
||||
/**
|
||||
* @param mixed $class
|
||||
* @param mixed $method
|
||||
* @return mixed
|
||||
*/
|
||||
public function execute(mixed $class, mixed $method = ''): mixed;
|
||||
|
||||
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Annotation;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri\Core\Str;
|
||||
use Kiri;
|
||||
use ReflectionException;
|
||||
use ReflectionProperty;
|
||||
|
||||
/**
|
||||
* Class Inject
|
||||
* @package Annotation
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)] class Inject extends Attribute
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Inject constructor.
|
||||
* @param string $value
|
||||
* @param array $construct
|
||||
*/
|
||||
public function __construct(public string $value, public array $construct = [])
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $class
|
||||
* @param mixed|null $method
|
||||
* @return bool
|
||||
* @throws ReflectionException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function execute(mixed $class, mixed $method = null): bool
|
||||
{
|
||||
if (!($method = $this->getProperty($class, $method))) {
|
||||
return false;
|
||||
}
|
||||
/** @var ReflectionProperty $class */
|
||||
$injectValue = static::parseInjectValue();
|
||||
if ($method->isPrivate() || $method->isProtected()) {
|
||||
$this->setter($class, $method, $injectValue);
|
||||
} else {
|
||||
$class->{$method->getName()} = $injectValue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $method
|
||||
* @param $injectValue
|
||||
*/
|
||||
private function setter($class, $method, $injectValue)
|
||||
{
|
||||
$method = 'set' . ucfirst(Str::convertUnderline($method->getName()));
|
||||
if (!method_exists($class, $method)) {
|
||||
return;
|
||||
}
|
||||
$class->$method($injectValue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $method
|
||||
* @return ReflectionProperty|bool
|
||||
*/
|
||||
private function getProperty($class, $method): ReflectionProperty|bool
|
||||
{
|
||||
if ($method instanceof ReflectionProperty && !$method->isStatic()) {
|
||||
return $method;
|
||||
}
|
||||
if (is_object($class)) $class = $class::class;
|
||||
$method = Kiri::getDi()->getClassReflectionProperty($class, $method);
|
||||
if (!$method || $method->isStatic()) {
|
||||
return false;
|
||||
}
|
||||
return $method;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
private function parseInjectValue(): mixed
|
||||
{
|
||||
if (!Kiri::app()->has($this->value)) {
|
||||
if (!empty($this->construct)) {
|
||||
return Kiri::getDi()->create($this->value, $this->construct);
|
||||
}
|
||||
return Kiri::getDi()->get($this->value);
|
||||
} else {
|
||||
return Kiri::app()->get($this->value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Annotation;
|
||||
|
||||
|
||||
use DirectoryIterator;
|
||||
use Exception;
|
||||
use Kiri;
|
||||
use Kiri\Abstracts\Component;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use Throwable;
|
||||
|
||||
|
||||
/**
|
||||
* Class Loader
|
||||
* @package Annotation
|
||||
*/
|
||||
class Loader extends Component
|
||||
{
|
||||
|
||||
|
||||
private array $_directory = [];
|
||||
|
||||
|
||||
private array $_methods = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @param $namespace
|
||||
* @throws Exception
|
||||
*/
|
||||
public function loader($path, $namespace)
|
||||
{
|
||||
$this->_scanDir(new DirectoryIterator($path), $namespace);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param object $handler
|
||||
* @return $this
|
||||
* @throws ReflectionException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function injectProperty(string $class, object $handler): static
|
||||
{
|
||||
$di = Kiri::getDi();
|
||||
|
||||
$reflect = $di->getReflect($class);
|
||||
|
||||
$di->propertyInject($reflect, $handler);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMethod(string $class, string $method = ''): array
|
||||
{
|
||||
if (!isset($this->_methods[$class])) {
|
||||
return [];
|
||||
}
|
||||
$properties = $this->_methods[$class];
|
||||
if (!empty($method) && isset($properties[$method])) {
|
||||
return $properties[$method];
|
||||
}
|
||||
return $properties;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param DirectoryIterator $paths
|
||||
* @param $namespace
|
||||
* @param array $exclude
|
||||
* @throws Exception
|
||||
*/
|
||||
public function _scanDir(DirectoryIterator $paths, $namespace, array $exclude = [])
|
||||
{
|
||||
foreach ($paths as $path) {
|
||||
if (function_exists('opcache_invalidate')) {
|
||||
opcache_invalidate($path->getRealPath(), true);
|
||||
}
|
||||
if ($path->isDot() || str_starts_with($path->getFilename(), '.')) {
|
||||
continue;
|
||||
}
|
||||
if ($this->inExclude($exclude, $path->getRealPath())) {
|
||||
continue;
|
||||
}
|
||||
if ($path->isDir()) {
|
||||
$iterator = new DirectoryIterator($path->getRealPath());
|
||||
$directory = rtrim($path->getRealPath(), '/');
|
||||
if (!isset($this->_directory[$directory])) {
|
||||
$this->_directory[$directory] = [];
|
||||
}
|
||||
$this->_scanDir($iterator, $namespace);
|
||||
} else {
|
||||
$this->readFile($path, $namespace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param DirectoryIterator $path
|
||||
* @param $namespace
|
||||
* @throws Exception
|
||||
*/
|
||||
private function readFile(DirectoryIterator $path, $namespace)
|
||||
{
|
||||
try {
|
||||
if ($path->getExtension() !== 'php') {
|
||||
return;
|
||||
}
|
||||
$replace = $this->getReflect($path, $namespace);
|
||||
if (!$replace || !$replace->getAttributes(Target::class)) {
|
||||
return;
|
||||
}
|
||||
$this->appendFileToDirectory($path->getRealPath(), $replace->getName());
|
||||
} catch (Throwable $throwable) {
|
||||
$this->error(jTraceEx($throwable), 'throwable');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param DirectoryIterator $path
|
||||
* @param string $namespace
|
||||
* @return ReflectionClass|null
|
||||
*/
|
||||
private function getReflect(DirectoryIterator $path, string $namespace): ?ReflectionClass
|
||||
{
|
||||
$class = $this->explodeFileName($path, $namespace);
|
||||
if (!class_exists($class)) {
|
||||
return null;
|
||||
}
|
||||
return Kiri::getDi()->getReflect($class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param array $exclude
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function loadByDirectory(string $path, array $exclude = []): array
|
||||
{
|
||||
try {
|
||||
$path = '/' . trim($path, '/');
|
||||
$paths = [];
|
||||
foreach ($this->_directory as $key => $_path) {
|
||||
$key = '/' . trim($key, '/');
|
||||
if (!str_starts_with($key, $path) || $this->inExclude($exclude, $path)) {
|
||||
continue;
|
||||
}
|
||||
unset($this->_directory[$key]);
|
||||
foreach ($_path as $item) {
|
||||
$paths[] = $item;
|
||||
}
|
||||
}
|
||||
return $paths;
|
||||
} catch (Throwable $exception) {
|
||||
$this->addError($exception, 'throwable');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $exclude
|
||||
* @param $path
|
||||
* @return bool
|
||||
*/
|
||||
private function inExclude(array $exclude, $path): bool
|
||||
{
|
||||
if (empty($exclude)) {
|
||||
return false;
|
||||
}
|
||||
foreach ($exclude as $value) {
|
||||
if (str_starts_with($path, $value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param DirectoryIterator $path
|
||||
* @param string $namespace
|
||||
* @return string
|
||||
*/
|
||||
private function explodeFileName(DirectoryIterator $path, string $namespace): string
|
||||
{
|
||||
$replace = str_replace(APP_PATH, '', $path->getRealPath());
|
||||
|
||||
$replace = str_replace('.php', '', $replace);
|
||||
$replace = str_replace(DIRECTORY_SEPARATOR, '\\', $replace);
|
||||
$explode = explode('\\', $replace);
|
||||
array_shift($explode);
|
||||
|
||||
return $namespace . '\\' . implode('\\', $explode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $filePath
|
||||
* @param string $className
|
||||
*/
|
||||
public function appendFileToDirectory(string $filePath, string $className)
|
||||
{
|
||||
$array = explode('/', $filePath);
|
||||
unset($array[count($array) - 1]);
|
||||
|
||||
$array = '/' . trim(implode('/', $array), '/');
|
||||
|
||||
$this->_directory[$array][] = $className;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Annotation;
|
||||
|
||||
use Kiri;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)] class Mapping extends Attribute
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
*/
|
||||
public function __construct(public string $class)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $class
|
||||
* @param mixed|string $method
|
||||
* @return mixed
|
||||
*/
|
||||
public function execute(mixed $class, mixed $method = ''): mixed
|
||||
{
|
||||
Kiri::getDi()->mapping($this->class, $class);
|
||||
|
||||
return parent::execute($class, $method);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Annotation\Route;
|
||||
|
||||
|
||||
use Kiri\Annotation\Attribute;
|
||||
|
||||
/**
|
||||
* Class Document
|
||||
* @package Annotation\Route
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_METHOD)] class Document extends Attribute
|
||||
{
|
||||
|
||||
const INTEGER = 'int';
|
||||
const STRING = 'string';
|
||||
const BOOLEAN = 'bool';
|
||||
const FLOAT = 'float';
|
||||
|
||||
const ALIAS = [
|
||||
self::INTEGER => '整数',
|
||||
self::STRING => '字符串',
|
||||
self::BOOLEAN => '布尔值',
|
||||
self::FLOAT => '浮点',
|
||||
];
|
||||
|
||||
|
||||
public function __construct(array $request, array $response)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Annotation\Route;
|
||||
|
||||
|
||||
use Kiri\Annotation\Attribute;
|
||||
use Kiri\Message\Handler\Abstracts\MiddlewareManager;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
|
||||
/**
|
||||
* Class Middleware
|
||||
* @package Annotation\Route
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class Middleware extends Attribute
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Interceptor constructor.
|
||||
* @param string|array $middleware
|
||||
* @throws
|
||||
*/
|
||||
public function __construct(public string|array $middleware)
|
||||
{
|
||||
if (is_string($this->middleware)) {
|
||||
$this->middleware = [$this->middleware];
|
||||
}
|
||||
$array = [];
|
||||
foreach ($this->middleware as $value) {
|
||||
if (!in_array(MiddlewareInterface::class, class_implements($value))) {
|
||||
throw new \Exception('The middleware');
|
||||
}
|
||||
$array[] = $value;
|
||||
}
|
||||
$this->middleware = $array;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $class
|
||||
* @param mixed|null $method
|
||||
* @return $this
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function execute(mixed $class, mixed $method = null): mixed
|
||||
{
|
||||
MiddlewareManager::add($class, $method, $this->middleware);
|
||||
return parent::execute($class, $method);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Annotation\Route;
|
||||
|
||||
|
||||
use Kiri\Annotation\Attribute;
|
||||
use Kiri\Message\Handler\Router;
|
||||
use Kiri;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class Route extends Attribute
|
||||
{
|
||||
|
||||
/**
|
||||
* Route constructor.
|
||||
* @param string $uri
|
||||
* @param string $method
|
||||
* @param string $version
|
||||
*/
|
||||
public function __construct(public string $uri, public string $method, public string $version = 'v.1.0')
|
||||
{
|
||||
$this->uri = '/' . ltrim($this->uri, '/');
|
||||
$this->method = strtoupper($this->method);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $class
|
||||
* @param mixed|null $method
|
||||
* @return bool
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function execute(mixed $class, mixed $method = null): bool
|
||||
{
|
||||
$di = Kiri::getDi()->get(Router::class);
|
||||
$di->addRoute($this->method, $this->uri, $class . '@' . $method);
|
||||
return parent::execute($class, $method);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Annotation\Route;
|
||||
|
||||
|
||||
use Kiri\Annotation\Attribute;
|
||||
|
||||
/**
|
||||
* Class Socket
|
||||
* @package Annotation
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_METHOD)] class Socket extends Attribute
|
||||
{
|
||||
|
||||
const CLOSE = 'CLOSE';
|
||||
const MESSAGE = 'MESSAGE';
|
||||
const HANDSHAKE = 'HANDSHAKE';
|
||||
|
||||
/**
|
||||
* Socket constructor.
|
||||
* @param string $event
|
||||
* @param string|null $uri
|
||||
* @param string $version
|
||||
*/
|
||||
public function __construct(string $event, ?string $uri = null, string $version = 'v.1.0')
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Annotation;
|
||||
|
||||
|
||||
/**
|
||||
* Class Target
|
||||
* @package Annotation
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)] class Target extends Attribute
|
||||
{
|
||||
|
||||
|
||||
const WORKER = 'worker';
|
||||
const ALL = 'any';
|
||||
const PROCESS = 'process';
|
||||
const TASK = 'task';
|
||||
|
||||
|
||||
/**
|
||||
* @param string $only
|
||||
*/
|
||||
public function __construct(string $only = Target::ALL)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Annotation;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri;
|
||||
use Kiri\Server\Tasker\AsyncTaskExecute;
|
||||
|
||||
|
||||
/**
|
||||
* Class Task
|
||||
* @package Annotation
|
||||
* Task任务
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS)] class Task extends Attribute
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Task constructor.
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct(public string $name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $class
|
||||
* @param mixed|null $method
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function execute(mixed $class, mixed $method = null): bool
|
||||
{
|
||||
$task = Kiri::getDi()->get(AsyncTaskExecute::class);
|
||||
$task->reg($this->name, $class);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
abstract class AbstractServer extends Component
|
||||
{
|
||||
|
||||
|
||||
public string $name = 'http';
|
||||
|
||||
|
||||
}
|
||||
@@ -1,451 +1,108 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/10/7 0007
|
||||
* Time: 2:13
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
|
||||
use Database\Connection;
|
||||
use Exception;
|
||||
use Kiri\Message\Handler\Router;
|
||||
use Kafka\KafkaProvider;
|
||||
use Kiri\Async;
|
||||
use Kiri;
|
||||
use Kiri\Annotation\Annotation as SAnnotation;
|
||||
use Kiri\Cache\Redis;
|
||||
use Kiri\Di\LocalService;
|
||||
use Kiri\Error\{ErrorHandler, Logger};
|
||||
use Kiri\Exception\{InitException, NotFindClassException};
|
||||
use ReflectionException;
|
||||
use Kiri\Server\{Contract\OnTaskInterface, Server, ServerManager, Tasker\AsyncTaskExecute};
|
||||
use Swoole\Table;
|
||||
|
||||
/**
|
||||
* Class BaseApplication
|
||||
* @package Kiri\Base
|
||||
*/
|
||||
abstract class BaseApplication extends Component
|
||||
{
|
||||
|
||||
use TraitApplication;
|
||||
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public string $storage = APP_PATH . 'storage';
|
||||
|
||||
public string $envPath = APP_PATH . '.env';
|
||||
|
||||
/**
|
||||
* Init constructor.
|
||||
*
|
||||
*
|
||||
* @throws
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
Kiri::init($this);
|
||||
|
||||
$config = sweep(APP_PATH . '/config');
|
||||
|
||||
$this->moreComponents();
|
||||
$this->parseInt($config);
|
||||
$this->parseEvents($config);
|
||||
$this->initErrorHandler();
|
||||
$this->enableEnvConfig();
|
||||
$this->mapping($config['mapping'] ?? []);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $mapping
|
||||
*/
|
||||
public function mapping(array $mapping)
|
||||
{
|
||||
$di = Kiri::getDi();
|
||||
foreach ($mapping as $interface => $class) {
|
||||
$di->mapping($interface, $class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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');
|
||||
$lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
ini_set('auto_detect_line_endings', $autodetect);
|
||||
|
||||
return $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 $name
|
||||
* @return mixed
|
||||
* @throws ReflectionException
|
||||
* @throws NotFindClassException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __get($name): mixed
|
||||
{
|
||||
if ($this->has($name)) {
|
||||
return $this->get($name);
|
||||
}
|
||||
return parent::__get($name); // TODO: Change the autogenerated stub
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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 OnTaskInterface $execute
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function task(OnTaskInterface $execute): void
|
||||
{
|
||||
di(AsyncTaskExecute::class)->execute($execute);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @throws InitException
|
||||
* @throws Exception
|
||||
*/
|
||||
private function addEvent($key, $value): void
|
||||
{
|
||||
if ($value instanceof \Closure || is_object($value)) {
|
||||
$this->eventProvider->on($key, $value, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (is_array($value)) {
|
||||
if (is_object($value[0]) && !($value[0] instanceof \Closure)) {
|
||||
$this->eventProvider->on($key, $value, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_string($value[0])) {
|
||||
$value[0] = Kiri::createObject($value[0]);
|
||||
$this->eventProvider->on($key, $value, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
foreach ($value as $item) {
|
||||
if (!is_callable($item, true)) {
|
||||
throw new InitException("Class does not hav callback.");
|
||||
}
|
||||
$this->eventProvider->on($key, $item, 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function clone($name): mixed
|
||||
{
|
||||
return clone $this->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function initErrorHandler()
|
||||
{
|
||||
$this->get('error')->register();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function get($name): mixed
|
||||
{
|
||||
return di(LocalService::class)->get($name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLocalIps(): mixed
|
||||
{
|
||||
return swoole_get_local_ip();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFirstLocal(): mixed
|
||||
{
|
||||
return current($this->getLocalIps());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Logger
|
||||
* @throws
|
||||
*/
|
||||
public function getLogger(): Logger
|
||||
{
|
||||
return $this->get('logger');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \Redis|Redis
|
||||
* @throws
|
||||
*/
|
||||
public function getRedis(): Redis|\Redis
|
||||
{
|
||||
return Kiri::getDi()->get(Redis::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $ip
|
||||
* @return bool
|
||||
*/
|
||||
public function isLocal($ip): bool
|
||||
{
|
||||
return $this->getFirstLocal() == $ip;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return ErrorHandler
|
||||
* @throws
|
||||
*/
|
||||
public function getError(): ErrorHandler
|
||||
{
|
||||
return $this->get('error');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return Table
|
||||
* @throws
|
||||
*/
|
||||
public function getTable($name): Table
|
||||
{
|
||||
return $this->get($name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Config
|
||||
* @throws
|
||||
*/
|
||||
public function getConfig(): Config
|
||||
{
|
||||
return $this->get('config');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Router
|
||||
* @throws
|
||||
*/
|
||||
public function getRouter(): Router
|
||||
{
|
||||
return Kiri::getDi()->get(Router::class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Server
|
||||
* @throws
|
||||
*/
|
||||
public function getServer(): Server
|
||||
{
|
||||
return Kiri::getDi()->get(Server::class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \Swoole\Http\Server|\Swoole\Server|\Swoole\WebSocket\Server|null
|
||||
* @throws
|
||||
*/
|
||||
public function getSwoole(): \Swoole\Http\Server|\Swoole\Server|\Swoole\WebSocket\Server|null
|
||||
{
|
||||
return di(ServerManager::class)->getServer();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return SAnnotation
|
||||
* @throws
|
||||
*/
|
||||
public function getAnnotation(): SAnnotation
|
||||
{
|
||||
return $this->get('Annotation');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Async
|
||||
* @throws
|
||||
*/
|
||||
public function getAsync(): Async
|
||||
{
|
||||
return $this->get('async');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $array
|
||||
*/
|
||||
private function setComponents($array): void
|
||||
{
|
||||
di(LocalService::class)->setComponents($array);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param $definition
|
||||
*/
|
||||
public function set($id, $definition): void
|
||||
{
|
||||
di(LocalService::class)->set($id, $definition);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
public function has($id): bool
|
||||
{
|
||||
return di(LocalService::class)->has($id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function moreComponents(): void
|
||||
{
|
||||
$this->setComponents([
|
||||
'error' => ['class' => ErrorHandler::class],
|
||||
'config' => ['class' => Config::class],
|
||||
'logger' => ['class' => Logger::class],
|
||||
'Annotation' => ['class' => SAnnotation::class],
|
||||
'databases' => ['class' => Connection::class],
|
||||
'async' => ['class' => Async::class],
|
||||
'kafka-container' => ['class' => KafkaProvider::class],
|
||||
]);
|
||||
}
|
||||
}
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/10/7 0007
|
||||
* Time: 2:13
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
|
||||
use Database\DatabasesProviders;
|
||||
use Exception;
|
||||
use Kiri\Events\EventInterface;
|
||||
use Kiri\Config\ConfigProvider;
|
||||
use Kiri\Exception\{InitException};
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Kiri\Events\EventProvider;
|
||||
use Kiri\Error\StdoutLogger;
|
||||
|
||||
/**
|
||||
* Class BaseApplication
|
||||
* @package Kiri\Base
|
||||
* @property DatabasesProviders $connections
|
||||
*/
|
||||
abstract class BaseApplication extends LocalService
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public string $storage = APP_PATH . 'storage';
|
||||
|
||||
|
||||
/**
|
||||
* @param EventProvider $provider
|
||||
* @param ConfigProvider $config
|
||||
* @param ContainerInterface $container
|
||||
* @throws
|
||||
*/
|
||||
public function __construct(public EventProvider $provider, public ConfigProvider $config, public ContainerInterface $container)
|
||||
{
|
||||
$this->mapping($config);
|
||||
$this->parseStorage($config);
|
||||
$this->parseEvents($config);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ConfigProvider $config
|
||||
* @return void
|
||||
*/
|
||||
public function mapping(ConfigProvider $config): void
|
||||
{
|
||||
$this->container->bind(LoggerInterface::class, new StdoutLogger());
|
||||
foreach ($config->get('mapping', []) as $interface => $class) {
|
||||
$this->container->set($interface, $class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ConfigProvider $config
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function parseStorage(ConfigProvider $config): void
|
||||
{
|
||||
$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
|
||||
*/
|
||||
public function parseEvents(ConfigProvider $config): void
|
||||
{
|
||||
$events = $config->get('events', []);
|
||||
foreach ($events as $key => $value) {
|
||||
if (is_string($value)) {
|
||||
$value = $this->container->get($value);
|
||||
if (!($value instanceof EventInterface)) {
|
||||
throw new Exception("Event listen must implement " . EventInterface::class);
|
||||
}
|
||||
$value = [$value, 'process'];
|
||||
}
|
||||
$this->provider->on($key, $value, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
|
||||
|
||||
use Swoole\Coroutine;
|
||||
|
||||
abstract class BaseContext
|
||||
{
|
||||
protected static array $pool = [];
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri\Core\Json;
|
||||
|
||||
/**
|
||||
* Class BaseGoto
|
||||
* @package Kiri\Abstracts
|
||||
*/
|
||||
class BaseGoto extends Component
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param int $statusCode
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function end(string $message, int $statusCode = 200): mixed
|
||||
{
|
||||
throw new Exception(Json::to(12350, $message), $statusCode);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
|
||||
abstract class Command extends Component
|
||||
{
|
||||
|
||||
}
|
||||
@@ -12,249 +12,88 @@ namespace Kiri\Abstracts;
|
||||
|
||||
use Exception;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Kiri\Di\Container;
|
||||
use Kiri\Events\EventDispatch;
|
||||
use Kiri\Events\EventProvider;
|
||||
use Kiri;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use Kiri\Error\StdoutLogger;
|
||||
use ReflectionException;
|
||||
|
||||
/**
|
||||
* Class Component
|
||||
* @package Kiri\Base
|
||||
* @property ContainerInterface|Container $container
|
||||
* @property EventProvider $eventProvider
|
||||
* @property EventDispatch $eventDispatch
|
||||
*/
|
||||
class Component implements Configure
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* BaseAbstract constructor.
|
||||
*
|
||||
* @param array $config
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
if (!empty($config) && is_array($config)) {
|
||||
Kiri::configure($this, $config);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* BaseAbstract constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Container|ContainerInterface
|
||||
*/
|
||||
#[Pure] public function getContainer(): ContainerInterface|Container
|
||||
{
|
||||
return Kiri::getDi();
|
||||
}
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return EventProvider
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
public function getEventProvider(): EventProvider
|
||||
{
|
||||
return $this->getContainer()->get(EventProvider::class);
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
#[Pure] public static function className(): string
|
||||
{
|
||||
return static::class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return EventDispatch
|
||||
*/
|
||||
protected function getEventDispatch(): EventDispatch
|
||||
{
|
||||
return $this->getContainer()->get(EventDispatch::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @return StdoutLogger
|
||||
* @throws
|
||||
*/
|
||||
public function getLogger(): StdoutLogger
|
||||
{
|
||||
return Kiri::getLogger();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
#[Pure] public static function className(): string
|
||||
{
|
||||
return static::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $value
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$method = 'set' . ucfirst($name);
|
||||
if (method_exists($this, $method)) {
|
||||
$this->{$method}($value);
|
||||
} else {
|
||||
throw new Exception('The set name ' . $name . ' not find in class ' . static::class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __get($name): mixed
|
||||
{
|
||||
$method = 'get' . ucfirst($name);
|
||||
if (method_exists($this, $method)) {
|
||||
return $this->$method();
|
||||
} else {
|
||||
throw new Exception('The get name ' . $name . ' not find in class ' . static::class);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function __get(string $name)
|
||||
{
|
||||
$method = 'get' . ucfirst($name);
|
||||
if (method_exists($this, $method)) {
|
||||
return $this->{$method}();
|
||||
} else if (method_exists($this, $name)) {
|
||||
return $this->{$name};
|
||||
} else {
|
||||
throw new Exception('Unable getting property ' . get_called_class() . '::' . $name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param string $model
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function addError($message, string $model = 'app'): bool
|
||||
{
|
||||
if ($message instanceof \Throwable) {
|
||||
$this->error($message = jTraceEx($message));
|
||||
} else {
|
||||
if (!is_string($message)) {
|
||||
$message = json_encode($message, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
$this->error($message);
|
||||
}
|
||||
Kiri::app()->getLogger()->fail($message, $model);
|
||||
return FALSE;
|
||||
}
|
||||
/**
|
||||
* @param string $name
|
||||
* @param $value
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function __set(string $name, $value): void
|
||||
{
|
||||
$method = 'set' . ucfirst($name);
|
||||
if (method_exists($this, $method)) {
|
||||
$this->{$method}($value);
|
||||
} else if (method_exists($this, $name)) {
|
||||
$this->{$name} = $value;
|
||||
} else {
|
||||
throw new Exception('Unable setting property ' . get_called_class() . '::' . $name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Logger
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function logger(): Logger
|
||||
{
|
||||
return Kiri::getDi()->get(Logger::class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $message
|
||||
* @param string $method
|
||||
* @param string $file
|
||||
* @throws Exception
|
||||
*/
|
||||
public function debug(mixed $message, string $method = '', string $file = '')
|
||||
{
|
||||
if (!is_string($message)) {
|
||||
$message = print_r($message, true);
|
||||
}
|
||||
$context = [];
|
||||
if (!empty($method)) $context['method'] = $method;
|
||||
if (!empty($file)) $context['file'] = $file;
|
||||
|
||||
$this->logger()->debug($message, $context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $message
|
||||
* @param string $method
|
||||
* @param string $file
|
||||
* @throws Exception
|
||||
*/
|
||||
public function info(mixed $message, string $method = '', string $file = '')
|
||||
{
|
||||
if (!is_string($message)) {
|
||||
$message = print_r($message, true);
|
||||
}
|
||||
$context = [];
|
||||
if (!empty($method)) $context['method'] = $method;
|
||||
if (!empty($file)) $context['file'] = $file;
|
||||
|
||||
$this->logger()->info($message, $context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $message
|
||||
* @param string $method
|
||||
* @param string $file
|
||||
* @throws Exception
|
||||
*/
|
||||
public function success(mixed $message, string $method = '', string $file = '')
|
||||
{
|
||||
if (!is_string($message)) {
|
||||
$message = print_r($message, true);
|
||||
}
|
||||
$context = [];
|
||||
if (!empty($method)) $context['method'] = $method;
|
||||
if (!empty($file)) $context['file'] = $file;
|
||||
|
||||
$this->logger()->notice($message, $context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $message
|
||||
* @param string $method
|
||||
* @param string $file
|
||||
* @throws Exception
|
||||
*/
|
||||
public function warning(mixed $message, string $method = '', string $file = '')
|
||||
{
|
||||
if (!is_string($message)) {
|
||||
$message = print_r($message, true);
|
||||
}
|
||||
|
||||
$context = [];
|
||||
if (!empty($method)) $context['method'] = $method;
|
||||
if (!empty($file)) $context['file'] = $file;
|
||||
|
||||
$this->logger()->critical($message, $context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $message
|
||||
* @param null $method
|
||||
* @param null $file
|
||||
* @throws Exception
|
||||
*/
|
||||
public function error(mixed $message, $method = null, $file = null)
|
||||
{
|
||||
if ($message instanceof \Throwable) {
|
||||
$message = $message->getMessage() . " on line " . $message->getLine() . " at file " . $message->getFile();
|
||||
}
|
||||
|
||||
$context = [];
|
||||
if (is_string($method)) {
|
||||
$message = (empty($method) ? '' : $method . ': ') . $message;
|
||||
} else {
|
||||
if (is_null($method)) {
|
||||
$method = [];
|
||||
}
|
||||
$context = $method;
|
||||
}
|
||||
if (!empty($method)) $context['method'] = $method;
|
||||
if (!empty($file)) $context['file'] = $file;
|
||||
|
||||
$this->logger()->error($message, $context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/5/24 0024
|
||||
* Time: 11:50
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
use Kiri\Exception\ConfigException;
|
||||
|
||||
|
||||
/**
|
||||
* Class Config
|
||||
* @package Kiri\Base
|
||||
*/
|
||||
class Config extends Component
|
||||
{
|
||||
|
||||
const ERROR_MESSAGE = 'The not find %s in app configs.';
|
||||
|
||||
protected static mixed $data = [];
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getData(): mixed
|
||||
{
|
||||
return static::$data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public static function setData($key, $value): mixed
|
||||
{
|
||||
return static::$data[$key] = $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $configs
|
||||
*/
|
||||
public static function sets(array $configs)
|
||||
{
|
||||
if (empty($configs)) {
|
||||
return;
|
||||
}
|
||||
static::$data = $configs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param bool $try
|
||||
* @param mixed|null $default
|
||||
* @return mixed
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public static function get($key, mixed $default = null, bool $try = FALSE): mixed
|
||||
{
|
||||
$instance = static::$data;
|
||||
if (!str_contains($key, '.')) {
|
||||
return $instance[$key] ?? $default;
|
||||
}
|
||||
foreach (explode('.', $key) as $value) {
|
||||
if (empty($value)) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($instance[$value])) {
|
||||
if ($try) {
|
||||
throw new ConfigException(sprintf(self::ERROR_MESSAGE, $key));
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
if (!is_array($instance[$value])) {
|
||||
return $instance[$value];
|
||||
}
|
||||
$instance = $instance[$value];
|
||||
}
|
||||
return empty($instance) ? $default : $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public static function set($key, $value): mixed
|
||||
{
|
||||
$explode = explode('.', $key);
|
||||
$parent = &static::$data;
|
||||
foreach ($explode as $item) {
|
||||
if (!isset($parent[$item])) {
|
||||
$parent[$item] = [];
|
||||
}
|
||||
$parent = &$parent[$item];
|
||||
}
|
||||
$parent = $value;
|
||||
|
||||
unset($parent);
|
||||
|
||||
return static::$data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param bool $must_not_null
|
||||
* @return bool
|
||||
*/
|
||||
public static function has($key, bool $must_not_null = false): bool
|
||||
{
|
||||
if (!isset(static::$data[$key])) {
|
||||
return false;
|
||||
}
|
||||
$config = static::$data[$key];
|
||||
if ($must_not_null === false) {
|
||||
return true;
|
||||
}
|
||||
return !empty($config);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
use Kiri\Coordinator;
|
||||
|
||||
class CoordinatorManager
|
||||
{
|
||||
|
||||
|
||||
|
||||
private static array $_waite = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param string $category
|
||||
* @return Coordinator
|
||||
*/
|
||||
public static function utility(string $category): Coordinator
|
||||
{
|
||||
if (!((static::$_waite[$category] ?? null) instanceof Coordinator)) {
|
||||
static::$_waite[$category] = new Coordinator();
|
||||
}
|
||||
return static::$_waite[$category];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
|
||||
use Kiri\Core\Dtl;
|
||||
|
||||
|
||||
/**
|
||||
* Interface IListener
|
||||
* @package Kiri\Abstracts
|
||||
*/
|
||||
interface IListener
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param Dtl $dtl
|
||||
* @return mixed
|
||||
*/
|
||||
public function execute(Dtl $dtl): mixed;
|
||||
|
||||
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
class Input
|
||||
{
|
||||
|
||||
private array $_argv = [];
|
||||
|
||||
|
||||
private string $_command = '';
|
||||
|
||||
|
||||
/**
|
||||
* Input constructor.
|
||||
* @param $argv
|
||||
* @throws
|
||||
*/
|
||||
public function __construct($argv)
|
||||
{
|
||||
$this->_argv = $this->resolve($argv);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCommandName(): string
|
||||
{
|
||||
return $this->_command;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param null $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key, $default = null): mixed
|
||||
{
|
||||
return $this->_argv[$key] ?? $default;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return bool
|
||||
*/
|
||||
public function exists($key): bool
|
||||
{
|
||||
return isset($this->_argv[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @return $this
|
||||
*/
|
||||
public function set($key, $value): static
|
||||
{
|
||||
$this->_argv[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return false|string
|
||||
*/
|
||||
public function toJson(): bool|string
|
||||
{
|
||||
return json_encode($this->_argv, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $parameters
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function resolve($parameters): array
|
||||
{
|
||||
$arrays = [];
|
||||
$parameters = array_slice($parameters, 1);
|
||||
if (empty($parameters)) {
|
||||
return $arrays;
|
||||
}
|
||||
$this->_command = array_shift($parameters);
|
||||
foreach ($parameters as $parameter) {
|
||||
$explode = explode('=', $parameter);
|
||||
if (count($explode) < 2) {
|
||||
continue;
|
||||
}
|
||||
$arrays[array_shift($explode)] = current($explode);
|
||||
}
|
||||
return $arrays;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCommand(): string
|
||||
{
|
||||
return $this->_command;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class Listener
|
||||
* @package Kiri\Abstracts
|
||||
* 监听的名称
|
||||
*/
|
||||
abstract class Listener extends Component implements IListener
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
use Exception;
|
||||
|
||||
class LocalService extends Component implements LocalServiceInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $_definition = [];
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $_components = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $name): bool
|
||||
{
|
||||
return isset($this->_definition[$name]) || isset($this->_components[$name]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function get(string $name): mixed
|
||||
{
|
||||
if (isset($this->_components[$name])) return $this->_components[$name];
|
||||
if (!isset($this->_definition[$name])) {
|
||||
throw new Exception('Undefined component ' . $name);
|
||||
}
|
||||
$definition = $this->_definition[$name];
|
||||
if (!($definition instanceof \Closure)) {
|
||||
$this->_components[$name] = \Kiri::createObject($definition);
|
||||
} else {
|
||||
$this->_components[$name] = call_user_func($definition);
|
||||
}
|
||||
return $this->_components[$name];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $value
|
||||
* @return void
|
||||
*/
|
||||
public function set(string $name, array $value): void
|
||||
{
|
||||
$this->_definition[$name] = $value;
|
||||
unset($this->_components[$name]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function __get(string $name)
|
||||
{
|
||||
if (!$this->has($name)) {
|
||||
return parent::__get($name);
|
||||
} else {
|
||||
return $this->get($name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
interface LocalServiceInterface
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
use DirectoryIterator;
|
||||
use Exception;
|
||||
use Kiri\Events\EventProvider;
|
||||
use Kiri\Exception\ConfigException;
|
||||
use Kiri;
|
||||
use Kiri\Server\Events\OnWorkerStop;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ReflectionException;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Logger implements LoggerInterface
|
||||
{
|
||||
|
||||
const EMERGENCY = 'emergency';
|
||||
const ALERT = 'alert';
|
||||
const CRITICAL = 'critical';
|
||||
const ERROR = 'error';
|
||||
const WARNING = 'warning';
|
||||
const NOTICE = 'notice';
|
||||
const INFO = 'info';
|
||||
const DEBUG = 'debug';
|
||||
|
||||
|
||||
private array $_loggers = [];
|
||||
|
||||
|
||||
const LOGGER_LEVELS = [Logger::EMERGENCY, Logger::ALERT, Logger::CRITICAL, Logger::ERROR, Logger::WARNING, Logger::NOTICE, Logger::INFO, Logger::DEBUG];
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
Kiri::getDi()->get(EventProvider::class)->on(OnWorkerStop::class, [$this, 'onAfterRequest']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
* @throws ConfigException
|
||||
*
|
||||
* 紧急情况
|
||||
*/
|
||||
public function emergency($message, array $context = [])
|
||||
{
|
||||
// TODO: Implement emergency() method.
|
||||
$this->log(Logger::EMERGENCY, $message, $context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
* @throws ConfigException
|
||||
*
|
||||
* 应该警惕的
|
||||
*/
|
||||
public function alert($message, array $context = [])
|
||||
{
|
||||
// TODO: Implement alert() method.
|
||||
$this->log(Logger::ALERT, $message, $context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
* @throws ConfigException
|
||||
*
|
||||
* 关键性的日志
|
||||
*/
|
||||
public function critical($message, array $context = [])
|
||||
{
|
||||
// TODO: Implement critical() method.
|
||||
$this->log(Logger::CRITICAL, $message, $context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function error($message, array $context = [])
|
||||
{
|
||||
// TODO: Implement error() method.
|
||||
$this->log(Logger::ERROR, $message, $context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function warning($message, array $context = [])
|
||||
{
|
||||
// TODO: Implement warning() method.
|
||||
$this->log(Logger::WARNING, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function notice($message, array $context = [])
|
||||
{
|
||||
// TODO: Implement notice() method.
|
||||
$this->log(Logger::NOTICE, $message, $context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function info($message, array $context = [])
|
||||
{
|
||||
// TODO: Implement info() method.
|
||||
$this->log(Logger::INFO, $message, $context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function debug($message, array $context = [])
|
||||
{
|
||||
// TODO: Implement debug() method.
|
||||
$this->log(Logger::DEBUG, $message, $context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $level
|
||||
* @param string $message
|
||||
* @param array $context
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function log($level, $message, array $context = [])
|
||||
{
|
||||
// TODO: Implement log() method.
|
||||
$levels = Config::get('log.level', Logger::LOGGER_LEVELS);
|
||||
if (!in_array($level, $levels) || str_contains($message, 'Event::rshutdown')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$_string = '[' . now() . '] production.' . $level . ': ' . $this->_string($message, $context);
|
||||
|
||||
file_put_contents('php://output', $_string);
|
||||
|
||||
$this->_loggers[] = $_string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param OnWorkerStop $param
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onAfterRequest(OnWorkerStop $param)
|
||||
{
|
||||
$loggers = implode(PHP_EOL, $this->_loggers);
|
||||
$this->_loggers = [];
|
||||
if (!empty($loggers)) {
|
||||
$filename = storage('log-' . date('Y-m-d') . '.log', 'log/');
|
||||
|
||||
file_put_contents($filename, $loggers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function flush()
|
||||
{
|
||||
$this->removeFile(storage());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $dirname
|
||||
* @return void
|
||||
*/
|
||||
private function removeFile(string $dirname)
|
||||
{
|
||||
$paths = new DirectoryIterator($dirname);
|
||||
/** @var DirectoryIterator $path */
|
||||
foreach ($paths as $path) {
|
||||
if ($path->isDot() || str_starts_with($path->getFilename(), '.')) {
|
||||
continue;
|
||||
}
|
||||
if ($path->isDir()) {
|
||||
$directory = rtrim($path->getRealPath(), '/');
|
||||
$this->removeFile($directory);
|
||||
}
|
||||
@unlink($path->getRealPath());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param $context
|
||||
* @return string
|
||||
*/
|
||||
private function _string($message, $context): string
|
||||
{
|
||||
if (!empty($context)) {
|
||||
return $message . ' ' . PHP_EOL . print_r($context, true) . PHP_EOL;
|
||||
}
|
||||
return $message . PHP_EOL;
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,9 @@ declare(strict_types=1);
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
|
||||
use Kiri\Application;
|
||||
|
||||
interface Provider
|
||||
{
|
||||
|
||||
public function onImport(Application $application);
|
||||
public function onImport();
|
||||
|
||||
}
|
||||
|
||||
@@ -4,12 +4,24 @@ declare(strict_types=1);
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
|
||||
use Kiri;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Class Providers
|
||||
* @package Kiri\Abstracts
|
||||
* @property-read ContainerInterface $container
|
||||
*/
|
||||
abstract class Providers extends Component implements Provider
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
public function getContainer(): ContainerInterface
|
||||
{
|
||||
return Kiri::getDi();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Abstracts;
|
||||
|
||||
|
||||
use Kiri\Annotation\Annotation as SAnnotation;
|
||||
use Database\Connection;
|
||||
use Database\DatabasesProviders;
|
||||
use Kiri\Message\Handler\Router;
|
||||
use Kiri\Server\Server;
|
||||
use Kiri\Async;
|
||||
use Kiri\Error\Logger;
|
||||
use Kiri\Jwt\JWTAuth;
|
||||
|
||||
/**
|
||||
* Trait TraitApplication
|
||||
* @package Kiri\Abstracts
|
||||
* @property Router $router
|
||||
* @property Server $server
|
||||
* @property DatabasesProviders $db
|
||||
* @property Async $async
|
||||
* @property Logger $logger
|
||||
* @property JWTAuth $jwt
|
||||
* @property SAnnotation $annotation
|
||||
* @property BaseGoto $goto
|
||||
* @property Connection $databases
|
||||
*/
|
||||
trait TraitApplication
|
||||
{
|
||||
|
||||
}
|
||||
+160
-260
@@ -1,260 +1,160 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/25 0025
|
||||
* Time: 18:38
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri;
|
||||
|
||||
|
||||
use Closure;
|
||||
use Database\DatabasesProviders;
|
||||
use Exception;
|
||||
use Kiri;
|
||||
use Kiri\Abstracts\{BaseApplication, Config, Kernel};
|
||||
use Kiri\Crontab\CrontabProviders;
|
||||
use Kiri\Events\{OnAfterCommandExecute, OnBeforeCommandExecute};
|
||||
use Kiri\FileListen\HotReload;
|
||||
use Kiri\Server\ServerProviders;
|
||||
use ReflectionException;
|
||||
use stdClass;
|
||||
use Swoole\Process;
|
||||
use Swoole\Timer;
|
||||
use Symfony\Component\Console\{Application as ConsoleApplication,
|
||||
Command\Command,
|
||||
Input\ArgvInput,
|
||||
Output\ConsoleOutput,
|
||||
Output\OutputInterface
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class Init
|
||||
*
|
||||
* @package Kiri
|
||||
*
|
||||
* @property-read Config $config
|
||||
*/
|
||||
class Application extends BaseApplication
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public string $id = 'uniqueId';
|
||||
|
||||
|
||||
public string $state = '';
|
||||
|
||||
|
||||
/** @var array<array<Process>> */
|
||||
private array $_process = [];
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->import(ServerProviders::class);
|
||||
|
||||
$this->register(Runtime::class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws
|
||||
*/
|
||||
public function withDatabase()
|
||||
{
|
||||
$this->import(DatabasesProviders::class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws
|
||||
*/
|
||||
public function withCrontab()
|
||||
{
|
||||
$this->import(CrontabProviders::class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param Process $process
|
||||
*/
|
||||
public function addProcess(string $class, Process $process)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Process[]
|
||||
*/
|
||||
public function getProcess(): array
|
||||
{
|
||||
return $this->_process;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @return Process|null
|
||||
*/
|
||||
public function getProcessName(string $class): ?Process
|
||||
{
|
||||
return $this->_process[$class] ?? null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws
|
||||
*/
|
||||
public function withFileChangeListen()
|
||||
{
|
||||
$container = Kiri::getDi();
|
||||
|
||||
$console = $container->get(ConsoleApplication::class);
|
||||
$console->add($container->get(HotReload::class));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Closure|array $closure
|
||||
* @return $this
|
||||
* @throws Exception
|
||||
*/
|
||||
public function middleware(Closure|array $closure): static
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bool $useTree
|
||||
* @return $this
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setUseTree(bool $useTree): static
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $service
|
||||
* @return $this
|
||||
* @throws
|
||||
*/
|
||||
public function import(string $service): static
|
||||
{
|
||||
if (!class_exists($service)) {
|
||||
return $this;
|
||||
}
|
||||
$class = Kiri::getDi()->get($service);
|
||||
if (method_exists($class, 'onImport')) {
|
||||
$class->onImport($this);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Kernel $kernel
|
||||
* @return $this
|
||||
*/
|
||||
public function commands(Kernel $kernel): static
|
||||
{
|
||||
foreach ($kernel->getCommands() as $command) {
|
||||
$this->register($command);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $command
|
||||
* @throws
|
||||
*/
|
||||
public function register(string $command)
|
||||
{
|
||||
di(ConsoleApplication::class)->add(di($command));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $argv
|
||||
* @return void
|
||||
*/
|
||||
public function execute(array $argv): void
|
||||
{
|
||||
ini_set('swoole.enable_preemptive_scheduler', 'On');
|
||||
ini_set('swoole.enable_library', 'On');
|
||||
[$input, $output] = $this->argument($argv);
|
||||
try {
|
||||
$console = di(ConsoleApplication::class);
|
||||
$command = $input->getFirstArgument();
|
||||
if (empty($command)) {
|
||||
$command = 'sw:server';
|
||||
}
|
||||
$command = $console->find($command);
|
||||
if ($command instanceof Command) {
|
||||
$this->enableFileChange($command, $input, $output);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$output->writeln(jTraceEx($exception));
|
||||
} finally {
|
||||
Timer::clearAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $argv
|
||||
* @return array
|
||||
*/
|
||||
private function argument($argv): array
|
||||
{
|
||||
return [new ArgvInput($argv), new ConsoleOutput()];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ReflectionException
|
||||
* @throws Exception
|
||||
*/
|
||||
private function enableFileChange(Command $class, $input, $output): void
|
||||
{
|
||||
fire(new OnBeforeCommandExecute());
|
||||
if (!($class instanceof HotReload)) {
|
||||
$config = Config::get('scanner', []);
|
||||
if (!empty($config)) {
|
||||
foreach ($config as $key => $value) {
|
||||
scan_directory($value, $key);
|
||||
}
|
||||
}
|
||||
scan_directory(MODEL_PATH, 'app\Model');
|
||||
}
|
||||
|
||||
$this->container->setBindings(OutputInterface::class, $output);
|
||||
|
||||
$class->run($input, $output);
|
||||
fire(new OnAfterCommandExecute());
|
||||
$output->writeln('ok' . PHP_EOL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $className
|
||||
* @param null $abstracts
|
||||
* @return stdClass
|
||||
* @throws Exception
|
||||
*/
|
||||
public function make($className, $abstracts = null): stdClass
|
||||
{
|
||||
return make($className, $abstracts);
|
||||
}
|
||||
}
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/25 0025
|
||||
* Time: 18:38
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri;
|
||||
use Kiri\Abstracts\{BaseApplication, Kernel};
|
||||
use Kiri\Di\Scanner;
|
||||
use Kiri\Error\ErrorHandler;
|
||||
use Kiri\Events\{OnAfterCommandExecute, OnBeforeCommandExecute};
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use ReflectionException;
|
||||
use Symfony\Component\Console\{Application as ConsoleApplication,
|
||||
Exception\ExceptionInterface,
|
||||
Input\ArgvInput,
|
||||
Output\ConsoleOutput,
|
||||
Output\OutputInterface
|
||||
};
|
||||
use Kiri\Server\ServerCommand;
|
||||
use Kiri\Di\Inject\Container;
|
||||
use function config;
|
||||
|
||||
/**
|
||||
* Class Init
|
||||
*
|
||||
* @package Kiri
|
||||
*/
|
||||
class Application extends BaseApplication
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public string $id = 'uniqueId';
|
||||
|
||||
|
||||
public string $state = '';
|
||||
|
||||
|
||||
/**
|
||||
* @var ErrorHandler
|
||||
*/
|
||||
#[Container(ErrorHandler::class)]
|
||||
public ErrorHandler $errorHandler;
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
$this->errorHandler->registerShutdownHandler(config('error.shutdown', []));
|
||||
$this->errorHandler->registerExceptionHandler(config('error.exception', []));
|
||||
$this->errorHandler->registerErrorHandler(config('error.error', []));
|
||||
$this->id = config('id', uniqid('id.'));
|
||||
|
||||
$this->provider->on(OnBeforeCommandExecute::class, [$this, 'beforeCommandExecute']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param OnBeforeCommandExecute $beforeCommandExecute
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function beforeCommandExecute(OnBeforeCommandExecute $beforeCommandExecute): void
|
||||
{
|
||||
if (!($beforeCommandExecute->command instanceof ServerCommand)) {
|
||||
$scanner = $this->container->get(Scanner::class);
|
||||
$scanner->load_directory(APP_PATH . 'app/');
|
||||
} else if (config('reload.hot', false) === false) {
|
||||
$scanner = $this->container->get(Scanner::class);
|
||||
$scanner->load_directory(APP_PATH . 'app/');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string ...$services
|
||||
* @return $this
|
||||
* @throws
|
||||
*/
|
||||
public function import(string ...$services): static
|
||||
{
|
||||
foreach ($services as $service) {
|
||||
if (!class_exists($service)) {
|
||||
continue;
|
||||
}
|
||||
/** @var Kiri\Abstracts\Provider $class */
|
||||
$class = $this->container->get($service);
|
||||
if (method_exists($class, 'onImport')) {
|
||||
$class->onImport();
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Kernel $kernel
|
||||
* @return $this
|
||||
* @throws
|
||||
*/
|
||||
public function commands(Kernel $kernel): static
|
||||
{
|
||||
foreach ($kernel->getCommands() as $command) {
|
||||
$this->command($command);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string ...$command
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function command(string ...$command): void
|
||||
{
|
||||
$console = $this->container->get(ConsoleApplication::class);
|
||||
foreach ($command as $value) {
|
||||
$console->add($this->container->get($value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $argv
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function execute(array $argv): void
|
||||
{
|
||||
/** @var ArgvInput $input */
|
||||
$input = $this->container->bind(ArgvInput::class, new ArgvInput($argv));
|
||||
|
||||
/** @var ConsoleOutput $output */
|
||||
$output = $this->container->bind(OutputInterface::class, new ConsoleOutput());
|
||||
|
||||
$console = $this->container->get(ConsoleApplication::class);
|
||||
$command = $console->find($input->getFirstArgument() ?? 'list');
|
||||
|
||||
fire(new OnBeforeCommandExecute($command));
|
||||
$command->run($input, $output);
|
||||
fire(new OnAfterCommandExecute($command));
|
||||
|
||||
$output->writeln('execute complete.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri\Abstracts\Component;
|
||||
use Kiri\Server\ServerManager;
|
||||
use Kiri\Server\Tasker\AsyncTaskExecute;
|
||||
use Kiri;
|
||||
/**
|
||||
* Class Async
|
||||
* @package Kiri
|
||||
*/
|
||||
class Async extends Component
|
||||
{
|
||||
|
||||
|
||||
private static array $_absences = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $handler
|
||||
*/
|
||||
public function addAsync(string $name, string $handler)
|
||||
{
|
||||
static::$_absences[$name] = $handler;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $params
|
||||
* @throws Exception
|
||||
*/
|
||||
public function dispatch(string $name, array $params = [])
|
||||
{
|
||||
$context = di(AsyncTaskExecute::class);
|
||||
$context->execute(static::$_absences[$name], $params);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Cache\Base;
|
||||
|
||||
use Exception;
|
||||
use Kiri\Abstracts\Logger;
|
||||
use Kiri\Events\EventProvider;
|
||||
use Kiri\Exception\RedisConnectException;
|
||||
use Kiri;
|
||||
use Kiri\Pool\StopHeartbeatCheck;
|
||||
use Kiri\Server\Events\OnWorkerExit;
|
||||
use RedisException;
|
||||
use Swoole\Timer;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Redis implements StopHeartbeatCheck
|
||||
{
|
||||
|
||||
const DB_ERROR_MESSAGE = 'The system is busy, please try again later.';
|
||||
|
||||
|
||||
private ?\Redis $pdo = null;
|
||||
|
||||
public string $host;
|
||||
|
||||
public int $port;
|
||||
|
||||
public int $database = 0;
|
||||
|
||||
public string $auth = '';
|
||||
|
||||
public string $prefix = '';
|
||||
|
||||
public int $timeout = 30;
|
||||
|
||||
public int $read_timeout = 30;
|
||||
|
||||
public array $pool = [];
|
||||
|
||||
private int $_timer = -1;
|
||||
|
||||
private int $_last = 0;
|
||||
|
||||
|
||||
private EventProvider $eventProvider;
|
||||
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config)
|
||||
{
|
||||
$this->host = $config['host'];
|
||||
$this->port = $config['port'];
|
||||
$this->database = $config['databases'];
|
||||
$this->auth = $config['auth'];
|
||||
$this->prefix = $config['prefix'];
|
||||
$this->timeout = $config['timeout'];
|
||||
$this->read_timeout = $config['read_timeout'];
|
||||
$this->pool = $config['pool'];
|
||||
}
|
||||
|
||||
|
||||
public function init()
|
||||
{
|
||||
$this->heartbeat_check();
|
||||
|
||||
$this->eventProvider = Kiri::getDi()->get(EventProvider::class);
|
||||
$this->eventProvider->on(OnWorkerExit::class, [$this, 'onWorkerExit']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param Kiri\Server\Events\OnWorkerExit $exit
|
||||
* @return void
|
||||
*/
|
||||
public function onWorkerExit(OnWorkerExit $exit)
|
||||
{
|
||||
$this->stopHeartbeatCheck();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function heartbeat_check(): void
|
||||
{
|
||||
|
||||
if ($this->_timer === -1) {
|
||||
$this->_timer = Timer::tick(1000, fn() => $this->waite());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private function waite(): void
|
||||
{
|
||||
try {
|
||||
if ($this->_timer === -1) {
|
||||
Kiri::getDi()->get(Logger::class)->critical('timer end');
|
||||
$this->stopHeartbeatCheck();
|
||||
}
|
||||
if (time() - $this->_last > intval($this->pool['tick'] ?? 60)) {
|
||||
$this->stopHeartbeatCheck();
|
||||
|
||||
$this->eventProvider->off(OnWorkerExit::class, [$this, 'stopHeartbeatCheck']);
|
||||
|
||||
$this->pdo = null;
|
||||
}
|
||||
} catch (\Throwable $throwable) {
|
||||
error($throwable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function stopHeartbeatCheck(): void
|
||||
{
|
||||
if ($this->_timer > -1) {
|
||||
Timer::clear($this->_timer);
|
||||
}
|
||||
$this->_timer = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
* @throws RedisConnectException|RedisException
|
||||
*/
|
||||
public function __call(string $name, array $arguments)
|
||||
{
|
||||
if (!method_exists($this, $name)) {
|
||||
return $this->_pdo()->{$name}(...$arguments);
|
||||
}
|
||||
return $this->{$name}(...$arguments);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \Redis
|
||||
* @throws RedisConnectException
|
||||
* @throws RedisException
|
||||
*/
|
||||
public function _pdo(): \Redis
|
||||
{
|
||||
if ($this->_timer === -1) {
|
||||
$this->heartbeat_check();
|
||||
}
|
||||
if (!($this->pdo instanceof \Redis) || !$this->pdo->ping('isOk')) {
|
||||
$this->pdo = $this->newClient();
|
||||
}
|
||||
return $this->pdo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \Redis
|
||||
* @throws RedisConnectException
|
||||
*/
|
||||
private function newClient(): \Redis
|
||||
{
|
||||
$redis = new \Redis();
|
||||
if (!$redis->connect($this->host, $this->port, $this->timeout)) {
|
||||
throw new RedisConnectException(sprintf('The Redis Connect %s::%d Fail.', $this->host, $this->port));
|
||||
}
|
||||
if (!empty($this->auth) && !$redis->auth($this->auth)) {
|
||||
throw new RedisConnectException(sprintf('Redis Error: %s, Host %s, Auth %s', $redis->getLastError(), $this->host, $this->auth));
|
||||
}
|
||||
if ($this->read_timeout < 0) {
|
||||
$this->read_timeout = 0;
|
||||
}
|
||||
$redis->select($this->database);
|
||||
if ($this->read_timeout > 0) {
|
||||
$redis->setOption(\Redis::OPT_READ_TIMEOUT, $this->read_timeout);
|
||||
}
|
||||
$redis->setOption(\Redis::OPT_PREFIX, $this->prefix);
|
||||
return $redis;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/5/2 0002
|
||||
* Time: 14:51
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Cache;
|
||||
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Kiri\Abstracts\Component;
|
||||
use Swoole\Coroutine\System;
|
||||
|
||||
/**
|
||||
* Class File
|
||||
* @package Kiri\Cache
|
||||
*/
|
||||
class File extends Component implements ICache
|
||||
{
|
||||
public string $path;
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $val
|
||||
* @return string|int
|
||||
*/
|
||||
public function set($key, $val): string|int
|
||||
{
|
||||
if (is_array($val) || is_object($val)) {
|
||||
$val = swoole_serialize($val);
|
||||
}
|
||||
$tmpFile = $this->getCacheKey($key);
|
||||
if (!$this->exists($tmpFile)) {
|
||||
touch($tmpFile);
|
||||
}
|
||||
return System::writeFile($tmpFile, $val, LOCK_EX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param array $hashKeys
|
||||
* @return array|bool
|
||||
*/
|
||||
public function hMGet($key, array $hashKeys): array|bool
|
||||
{
|
||||
$hash = $this->get($key);
|
||||
if (!is_array($hash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$nowHash = [];
|
||||
foreach ($hashKeys as $hashKey) {
|
||||
$nowHash[$hashKey] = $hash[$hashKey] ?? null;
|
||||
}
|
||||
return $nowHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param array $val
|
||||
* @return bool|int|string
|
||||
*/
|
||||
public function hMSet($key, array $val): bool|int|string
|
||||
{
|
||||
$hash = $this->get($key);
|
||||
if (!is_array($hash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$merge = array_merge($hash, $val);
|
||||
return $this->set($key, $merge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $hashKey
|
||||
* @return string|int|bool
|
||||
*/
|
||||
public function hGet(string $key, string $hashKey): string|int|bool
|
||||
{
|
||||
$hash = $this->get($key);
|
||||
if (!is_array($hash)) {
|
||||
return false;
|
||||
}
|
||||
return $hash[$hashKey] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $hashKey
|
||||
* @param $hashValue
|
||||
* @return bool|int|string
|
||||
*/
|
||||
public function hSet($key, $hashKey, $hashValue): bool|int|string
|
||||
{
|
||||
$hash = $this->get($key);
|
||||
if (!is_array($hash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hash[$hashKey] = $hashValue;
|
||||
|
||||
return $this->set($key, $hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return bool
|
||||
*/
|
||||
#[Pure] public function exists($key): bool
|
||||
{
|
||||
return file_exists($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return mixed|bool
|
||||
*/
|
||||
public function get($key): string|bool
|
||||
{
|
||||
$tmpFile = $this->getCacheKey($key);
|
||||
if (!$this->exists($tmpFile)) {
|
||||
return false;
|
||||
}
|
||||
$content = file_get_contents($tmpFile);
|
||||
return swoole_unserialize($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return string
|
||||
* @throws
|
||||
*/
|
||||
private function getCacheKey($key): string
|
||||
{
|
||||
return storage($key, 'cache');
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/11/8 0008
|
||||
* Time: 16:35
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Cache;
|
||||
|
||||
/**
|
||||
* Interface ICache
|
||||
* @package Kiri\Cache
|
||||
*/
|
||||
interface ICache
|
||||
{
|
||||
/**
|
||||
* @param $key
|
||||
* @param $val
|
||||
* @return string|int
|
||||
*/
|
||||
public function set($key, $val): string|int;
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return string|int|bool
|
||||
*/
|
||||
public function get($key): string|int|bool;
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param array $hashKeys
|
||||
* @return array|bool|null
|
||||
*/
|
||||
public function hMGet($key, array $hashKeys): array|bool|null;
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param array $val
|
||||
* @return mixed
|
||||
*/
|
||||
public function hMSet($key, array $val): mixed;
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $hashKey
|
||||
* @return string|int|bool
|
||||
*/
|
||||
public function hGet(string $key, string $hashKey): string|int|bool;
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $hashKey
|
||||
* @param $hashValue
|
||||
* @return mixed
|
||||
*/
|
||||
public function hSet($key, $hashKey, $hashValue): mixed;
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return bool
|
||||
*/
|
||||
public function exists($key): bool;
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/27 0027
|
||||
* Time: 11:00
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Cache;
|
||||
|
||||
use Exception;
|
||||
use Kiri\Abstracts\Component;
|
||||
use Kiri\Abstracts\Config;
|
||||
use Kiri\Core\Json;
|
||||
use Kiri\Events\EventProvider;
|
||||
use Kiri\Exception\ConfigException;
|
||||
use Kiri;
|
||||
use Kiri\Pool\Redis as PoolRedis;
|
||||
use Kiri\Annotation\Inject;
|
||||
use Kiri\Server\Events\OnWorkerExit;
|
||||
use Swoole\Timer;
|
||||
|
||||
/**
|
||||
* Class Redis
|
||||
* @package Kiri\Cache
|
||||
* @mixin \Redis
|
||||
*/
|
||||
class Redis extends Component
|
||||
{
|
||||
|
||||
|
||||
const REDIS_OPTION_HOST = 'host';
|
||||
const REDIS_OPTION_PORT = 'port';
|
||||
const REDIS_OPTION_PREFIX = 'prefix';
|
||||
const REDIS_OPTION_AUTH = 'auth';
|
||||
const REDIS_OPTION_DATABASES = 'databases';
|
||||
const REDIS_OPTION_TIMEOUT = 'timeout';
|
||||
const REDIS_OPTION_POOL = 'pool';
|
||||
const REDIS_OPTION_POOL_TICK = 'tick';
|
||||
const REDIS_OPTION_POOL_MIN = 'min';
|
||||
const REDIS_OPTION_POOL_MAX = 'max';
|
||||
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$connections = Kiri::getDi()->get(PoolRedis::class);
|
||||
|
||||
$config = $this->get_config();
|
||||
|
||||
$length = Config::get('cache.redis.pool.max', 10);
|
||||
|
||||
$this->eventProvider->on(OnWorkerExit::class, [$this, 'destroy'], 0);
|
||||
|
||||
$connections->initConnections('Redis:' . $config['host'], true, $length);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function __call($name, $arguments): mixed
|
||||
{
|
||||
$time = microtime(true);
|
||||
if (method_exists($this, $name)) {
|
||||
$data = $this->{$name}(...$arguments);
|
||||
} else {
|
||||
$data = $this->proxy($name, $arguments);
|
||||
}
|
||||
if (microtime(true) - $time >= 0.02) {
|
||||
$this->warning('Redis:' . Json::encode([$name, $arguments]) . (microtime(true) - $time));
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param int $timeout
|
||||
* @return bool
|
||||
*/
|
||||
public function waite($key, int $timeout = 5): bool
|
||||
{
|
||||
$time = time();
|
||||
while (!$this->setNx($key, 1)) {
|
||||
if (time()- $time >= $timeout) {
|
||||
return FALSE;
|
||||
}
|
||||
usleep(1000);
|
||||
}
|
||||
$this->expire($key, $timeout);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param int $timeout
|
||||
* @return bool|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function lock($key, int $timeout = 5): bool|int
|
||||
{
|
||||
$script = <<<SCRIPT
|
||||
local _nx = redis.call('setnx',KEYS[1], ARGV[1])
|
||||
if (_nx ~= 0) then
|
||||
redis.call('expire',KEYS[1], ARGV[1])
|
||||
return 1
|
||||
end
|
||||
return 0
|
||||
SCRIPT;
|
||||
return $this->eval($script, ['{lock}:' . $key, $timeout], 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function unlock($key): int
|
||||
{
|
||||
return $this->del('{lock}:' . $key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function release()
|
||||
{
|
||||
$connections = Kiri::getDi()->get(PoolRedis::class);
|
||||
$connections->release($this->get_config(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁连接池
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function destroy()
|
||||
{
|
||||
$connections = Kiri::getDi()->get(PoolRedis::class);
|
||||
$connections->connection_clear($this->get_config(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
* @return mixed
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function proxy($name, $arguments): mixed
|
||||
{
|
||||
$connections = Kiri::getDi()->get(PoolRedis::class);
|
||||
|
||||
$config = $this->get_config();
|
||||
|
||||
$client = $connections->get($config, true);
|
||||
if (!($client instanceof Base\Redis)) {
|
||||
throw new Exception('Redis connections more.');
|
||||
}
|
||||
$response = $client->{$name}(...$arguments);
|
||||
$this->release();
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function get_config(): array
|
||||
{
|
||||
return Config::get('cache.redis', null, true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Config;
|
||||
|
||||
use Kiri\Core\HashMap;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
|
||||
private HashMap $hashMap;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->hashMap = new HashMap();
|
||||
$this->load(sweep(APP_PATH . 'config'));
|
||||
|
||||
$this->enableEnvConfig(APP_PATH . '.env');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $key, mixed $default = null): mixed
|
||||
{
|
||||
$keys = explode('.', $key);
|
||||
|
||||
$hashMap = $this->hashMap->get(array_shift($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 string $key
|
||||
* @param mixed $value
|
||||
* @return bool
|
||||
*/
|
||||
public function modify(string $key, mixed $value): bool
|
||||
{
|
||||
$keys = explode('.', $key);
|
||||
|
||||
$hashMap = $this->hashMap->get(array_shift($keys));
|
||||
if (is_null($hashMap)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$setting = &$hashMap;
|
||||
foreach ($keys as $k => $val) {
|
||||
if (!is_array($val)) {
|
||||
unset($setting);
|
||||
return false;
|
||||
}
|
||||
$setting = &$setting[$k];
|
||||
}
|
||||
|
||||
$setting = $value;
|
||||
unset($setting);
|
||||
|
||||
return $this->get($key) == $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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, '=');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,209 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri;
|
||||
|
||||
use Kiri\Abstracts\BaseContext;
|
||||
use Swoole\Coroutine;
|
||||
use Kiri;
|
||||
/**
|
||||
* Class Context
|
||||
* @package Yoc\http
|
||||
*/
|
||||
class Context extends BaseContext
|
||||
{
|
||||
|
||||
protected static array $_contents = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param $context
|
||||
* @param null $coroutineId
|
||||
* @return mixed
|
||||
*/
|
||||
public static function setContext($id, $context, $coroutineId = null): mixed
|
||||
{
|
||||
if (is_null($coroutineId)) {
|
||||
$coroutineId = Coroutine::getCid();
|
||||
}
|
||||
if (Coroutine::getCid() !== -1) {
|
||||
return Coroutine::getContext($coroutineId)[$id] = $context;
|
||||
}
|
||||
return static::$_contents[$id] = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param int $value
|
||||
* @param null $coroutineId
|
||||
* @return bool|int
|
||||
*/
|
||||
public static function increment($id, int $value = 1, $coroutineId = null): bool|int
|
||||
{
|
||||
if (is_null($coroutineId)) {
|
||||
$coroutineId = Coroutine::getCid();
|
||||
}
|
||||
if (!isset(Coroutine::getContext($coroutineId)[$id])) {
|
||||
Coroutine::getContext($coroutineId)[$id] = 0;
|
||||
}
|
||||
return Coroutine::getContext($coroutineId)[$id] += $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param int $value
|
||||
* @param null $coroutineId
|
||||
* @return bool|int
|
||||
*/
|
||||
public static function decrement($id, int $value = 1, $coroutineId = null): bool|int
|
||||
{
|
||||
if (is_null($coroutineId)) {
|
||||
$coroutineId = Coroutine::getCid();
|
||||
}
|
||||
if (!isset(Coroutine::getContext($coroutineId)[$id])) {
|
||||
Coroutine::getContext($coroutineId)[$id] = 0;
|
||||
}
|
||||
return Coroutine::getContext($coroutineId)[$id] -= $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param null $default
|
||||
* @param null $coroutineId
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getContext($id, $default = null, $coroutineId = null): mixed
|
||||
{
|
||||
if (Coroutine::getCid() === -1) {
|
||||
return static::loadByStatic($id, $default);
|
||||
}
|
||||
return static::loadByContext($id, $default, $coroutineId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param null $default
|
||||
* @param null $coroutineId
|
||||
* @return mixed
|
||||
*/
|
||||
private static function loadByContext($id, $default = null, $coroutineId = null): mixed
|
||||
{
|
||||
if (is_null($coroutineId)) {
|
||||
$coroutineId = Coroutine::getCid();
|
||||
}
|
||||
return Coroutine::getContext($coroutineId)[$id] ?? $default;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param null $default
|
||||
* @return mixed
|
||||
*/
|
||||
private static function loadByStatic($id, $default = null): mixed
|
||||
{
|
||||
return static::$_contents[$id] ?? $default;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param null $coroutineId
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getAllContext($coroutineId = null): mixed
|
||||
{
|
||||
if (Coroutine::getCid() === -1) {
|
||||
return Coroutine::getContext($coroutineId) ?? [];
|
||||
} else {
|
||||
return static::$_contents ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param null $coroutineId
|
||||
*/
|
||||
public static function remove(string $id, $coroutineId = null)
|
||||
{
|
||||
if (is_null($coroutineId)) {
|
||||
$coroutineId = Coroutine::getCid();
|
||||
}
|
||||
if (!static::hasContext($id, $coroutineId)) {
|
||||
return;
|
||||
}
|
||||
if (Coroutine::getCid() === -1) {
|
||||
unset(static::$_contents[$id]);
|
||||
} else {
|
||||
unset(Coroutine::getContext($coroutineId)[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param null $key
|
||||
* @param null $coroutineId
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasContext($id, $key = null, $coroutineId = null): bool
|
||||
{
|
||||
if (Coroutine::getCid() === -1) {
|
||||
return static::searchByStatic($id, $key);
|
||||
}
|
||||
return static::searchByCoroutine($id, $key, $coroutineId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param null $key
|
||||
* @return bool
|
||||
*/
|
||||
private static function searchByStatic($id, $key = null): bool
|
||||
{
|
||||
if (!isset(static::$_contents[$id])) {
|
||||
return false;
|
||||
}
|
||||
$value = static::$_contents[$id];
|
||||
if (!empty($key) && is_array($value)) {
|
||||
return isset($value[$key]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param null $key
|
||||
* @param null $coroutineId
|
||||
* @return bool
|
||||
*/
|
||||
private static function searchByCoroutine($id, $key = null, $coroutineId = null): bool
|
||||
{
|
||||
if (is_null($coroutineId)) {
|
||||
$coroutineId = Coroutine::getCid();
|
||||
}
|
||||
if (!isset(Coroutine::getContext($coroutineId)[$id])) {
|
||||
return false;
|
||||
}
|
||||
$value = Coroutine::getContext($coroutineId)[$id];
|
||||
if ($key !== null && is_array($value)) {
|
||||
return isset($value[$key]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function inCoroutine(): bool
|
||||
{
|
||||
return Coroutine::getCid() !== -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Kiri;
|
||||
|
||||
class Coordinator
|
||||
{
|
||||
|
||||
const string WORKER_START = 'worker:start';
|
||||
|
||||
private bool $waite = false;
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function yield(): void
|
||||
{
|
||||
if ($this->waite === false) {
|
||||
return;
|
||||
}
|
||||
$this->yield();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function waite(): void
|
||||
{
|
||||
$this->waite = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function done(): void
|
||||
{
|
||||
$this->waite = false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -10,8 +10,6 @@ declare(strict_types=1);
|
||||
namespace Kiri\Core;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class ArrayAccess
|
||||
* @package Kiri\Core
|
||||
@@ -19,82 +17,82 @@ use Exception;
|
||||
class ArrayAccess
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function toArray($data): array
|
||||
{
|
||||
if (!is_object($data) && !is_array($data)) {
|
||||
return [];
|
||||
}
|
||||
if (is_object($data)) {
|
||||
$data = self::objToArray($data);
|
||||
}
|
||||
$tmp = [];
|
||||
if (!is_array($data)) {
|
||||
return $tmp;
|
||||
}
|
||||
foreach ($data as $key => $val) {
|
||||
if (is_array($val) || is_object($val)) {
|
||||
$tmp[$key] = self::toArray($val);
|
||||
} else {
|
||||
$tmp[$key] = $val;
|
||||
}
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
/**
|
||||
* @param $data
|
||||
* @return array
|
||||
* @throws
|
||||
*/
|
||||
public static function toArray($data): array
|
||||
{
|
||||
if (!is_object($data) && !is_array($data)) {
|
||||
return [];
|
||||
}
|
||||
if (is_object($data)) {
|
||||
$data = self::objToArray($data);
|
||||
}
|
||||
$tmp = [];
|
||||
if (!is_array($data)) {
|
||||
return $tmp;
|
||||
}
|
||||
foreach ($data as $key => $val) {
|
||||
if (is_array($val) || is_object($val)) {
|
||||
$tmp[$key] = self::toArray($val);
|
||||
} else {
|
||||
$tmp[$key] = $val;
|
||||
}
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function objToArray($data): array
|
||||
{
|
||||
if (!is_object($data)) {
|
||||
return $data;
|
||||
}
|
||||
if (method_exists($data, 'get')) {
|
||||
$data = $data->get();
|
||||
if (is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
if (method_exists($data, 'toArray')) {
|
||||
$data = $data->toArray();
|
||||
} else {
|
||||
$data = get_object_vars((object)$data);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
/**
|
||||
* @param $data
|
||||
* @return array
|
||||
* @throws
|
||||
*/
|
||||
public static function objToArray($data): array
|
||||
{
|
||||
if (!is_object($data)) {
|
||||
return $data;
|
||||
}
|
||||
if (method_exists($data, 'get')) {
|
||||
$data = $data->get();
|
||||
if (is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
if (method_exists($data, 'toArray')) {
|
||||
$data = $data->toArray();
|
||||
} else {
|
||||
$data = get_object_vars((object)$data);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $oldArray
|
||||
* @param array $newArray
|
||||
* @return array
|
||||
*/
|
||||
public static function merge(array $oldArray, array $newArray): array
|
||||
{
|
||||
if (empty($oldArray)) {
|
||||
return $newArray;
|
||||
} else if (empty($newArray)) {
|
||||
return $oldArray;
|
||||
}
|
||||
foreach ($newArray as $item => $value) {
|
||||
if (!isset($oldArray[$item])) {
|
||||
$oldArray[$item] = $value;
|
||||
}
|
||||
if (is_array($value)) {
|
||||
$oldArray[$item] = self::merge($oldArray[$item], $value);
|
||||
} else {
|
||||
$oldArray[$item] = $value;
|
||||
}
|
||||
}
|
||||
return $oldArray;
|
||||
}
|
||||
/**
|
||||
* @param array $oldArray
|
||||
* @param array $newArray
|
||||
* @return array
|
||||
*/
|
||||
public static function merge(array $oldArray, array $newArray): array
|
||||
{
|
||||
if (empty($oldArray)) {
|
||||
return $newArray;
|
||||
} else if (empty($newArray)) {
|
||||
return $oldArray;
|
||||
}
|
||||
foreach ($newArray as $item => $value) {
|
||||
if (!isset($oldArray[$item])) {
|
||||
$oldArray[$item] = $value;
|
||||
}
|
||||
if (is_array($value)) {
|
||||
$oldArray[$item] = self::merge($oldArray[$item], $value);
|
||||
} else {
|
||||
$oldArray[$item] = $value;
|
||||
}
|
||||
}
|
||||
return $oldArray;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ declare(strict_types=1);
|
||||
namespace Kiri\Core;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class DateFormat
|
||||
* @package Kiri\Core
|
||||
@@ -18,87 +17,112 @@ namespace Kiri\Core;
|
||||
class DateFormat
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $time
|
||||
* @return bool|false|int|string
|
||||
*/
|
||||
private static function check($time): bool|int|string
|
||||
{
|
||||
if ($time === null) {
|
||||
$time = time();
|
||||
} else if (is_numeric($time)) {
|
||||
$length = strlen((string)$time);
|
||||
if ($length != 10 && $length != 13) {
|
||||
return false;
|
||||
}
|
||||
} else if (is_string($time)) {
|
||||
$time = strtotime($time);
|
||||
}
|
||||
|
||||
if (date('Y-m-d', $time)) {
|
||||
return $time;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public static function DaySecond(): int
|
||||
{
|
||||
$time = strtotime(date('Y-m-d', strtotime('+1days')));
|
||||
|
||||
return $time - time();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param null $time
|
||||
* @return bool|false|int
|
||||
*
|
||||
* 获取指定日期当周第一天的时间
|
||||
*/
|
||||
public static function getWeekCurrentDay($time = null): bool|int
|
||||
{
|
||||
if (!($time = static::check($time))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$time = strtotime('-' . (date('N') - 1) . 'days', $time);
|
||||
|
||||
return strtotime(date('Y-m-d'), $time);
|
||||
}
|
||||
/**
|
||||
* @param int $time
|
||||
* @return array
|
||||
*/
|
||||
public static function timeFromStrDate(int $time): array
|
||||
{
|
||||
$year = date('Y', $time);
|
||||
$month = date('m', $time);
|
||||
$day = date('d', $time);
|
||||
return [$year, $month, $day];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param null $time
|
||||
* @return bool|false|int
|
||||
*
|
||||
* 获取指定日期当月第一天的时间
|
||||
*/
|
||||
public static function getMonthCurrentDay($time = null): bool|int
|
||||
{
|
||||
if (!($time = static::check($time))) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @param $time
|
||||
* @return bool|false|int|string
|
||||
*/
|
||||
private static function check($time): bool|int|string
|
||||
{
|
||||
if ($time === null) {
|
||||
$time = time();
|
||||
} else if (is_numeric($time)) {
|
||||
$length = strlen((string)$time);
|
||||
if ($length != 10 && $length != 13) {
|
||||
return false;
|
||||
}
|
||||
} else if (is_string($time)) {
|
||||
$time = strtotime($time);
|
||||
}
|
||||
|
||||
return strtotime(date('Y-m', $time) . '-01');
|
||||
}
|
||||
if (date('Y-m-d', $time)) {
|
||||
return $time;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $time
|
||||
* @return bool|int|string 指定的月份有几天
|
||||
* 指定的月份有几天
|
||||
*/
|
||||
public static function getMonthTotalDay($time): bool|int|string
|
||||
{
|
||||
if (!($time = static::check($time))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return date('t', $time);
|
||||
}
|
||||
/**
|
||||
* @param null $time
|
||||
* @return bool|false|int
|
||||
*
|
||||
* 获取指定日期当周第一天的时间
|
||||
*/
|
||||
public static function getWeekCurrentDay($time = null): bool|int
|
||||
{
|
||||
if (!($time = static::check($time))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $startTime
|
||||
* @param null $endTime
|
||||
* @return string
|
||||
*/
|
||||
public static function mtime($startTime, $endTime = null)
|
||||
{
|
||||
if ($endTime === null) {
|
||||
$endTime = microtime(true);
|
||||
}
|
||||
return sprintf('%.7f', $endTime - $startTime);
|
||||
}
|
||||
$time = strtotime('-' . (date('N') - 1) . 'days', $time);
|
||||
|
||||
return strtotime(date('Y-m-d'), $time);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param null $time
|
||||
* @return bool|false|int
|
||||
*
|
||||
* 获取指定日期当月第一天的时间
|
||||
*/
|
||||
public static function getMonthCurrentDay($time = null): bool|int
|
||||
{
|
||||
if (!($time = static::check($time))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strtotime(date('Y-m', $time) . '-01');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $time
|
||||
* @return bool|int|string 指定的月份有几天
|
||||
* 指定的月份有几天
|
||||
*/
|
||||
public static function getMonthTotalDay($time): bool|int|string
|
||||
{
|
||||
if (!($time = static::check($time))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return date('t', $time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $startTime
|
||||
* @param null $endTime
|
||||
* @return string
|
||||
*/
|
||||
public static function mtime($startTime, $endTime = null): string
|
||||
{
|
||||
if ($endTime === null) {
|
||||
$endTime = microtime(true);
|
||||
}
|
||||
return sprintf('%.7f', $endTime - $startTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Kiri\Core;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri\Abstracts\Component;
|
||||
|
||||
/**
|
||||
* Class Dtl
|
||||
* @package Kiri\Core
|
||||
*/
|
||||
class Dtl extends Component
|
||||
{
|
||||
|
||||
protected array $params;
|
||||
|
||||
|
||||
/**
|
||||
* Dtl constructor.
|
||||
* @param $params
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct($params)
|
||||
{
|
||||
parent::__construct([]);
|
||||
$this->params = $params;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->params;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get($name): mixed
|
||||
{
|
||||
$array = $this->toArray();
|
||||
if (!isset($array[$name])) {
|
||||
return null;
|
||||
}
|
||||
return $array[$name];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+131
-75
@@ -2,100 +2,156 @@
|
||||
|
||||
namespace Kiri\Core;
|
||||
|
||||
use Exception;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use ReturnTypeWillChange;
|
||||
use Traversable;
|
||||
|
||||
class HashMap implements \ArrayAccess
|
||||
class HashMap implements \ArrayAccess, \IteratorAggregate
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private array $lists = [];
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private array $lists = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param $value
|
||||
*/
|
||||
public function put(string $key, $value)
|
||||
{
|
||||
$this->lists[$key] = $value;
|
||||
}
|
||||
/**
|
||||
* @return Traversable
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
return new \ArrayIterator($this->lists);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
#[Pure] public function get(string $key): mixed
|
||||
{
|
||||
if (!$this->has($key)) {
|
||||
return null;
|
||||
}
|
||||
return $this->lists[$key];
|
||||
}
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasItem(): bool
|
||||
{
|
||||
return count($this->lists) > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*/
|
||||
public function del(string $key)
|
||||
{
|
||||
if (!$this->has($key)) {
|
||||
return;
|
||||
}
|
||||
unset($this->lists[$key]);
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @param $value
|
||||
*/
|
||||
public function put(string $key, $value): void
|
||||
{
|
||||
$this->lists[$key] = $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $key): bool
|
||||
{
|
||||
return array_key_exists($key, $this->lists);
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @param $value
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function append(string $key, $value): void
|
||||
{
|
||||
if (!$this->has($key)) {
|
||||
$this->lists[$key] = [];
|
||||
} else if (!is_array($this->lists[$key])) {
|
||||
throw new Exception('Source must a array.');
|
||||
}
|
||||
$this->lists[$key][] = $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
return isset($this->lists[$offset]);
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed|null $default
|
||||
* @return mixed
|
||||
*/
|
||||
#[Pure] public function get(string $key, mixed $default = null): mixed
|
||||
{
|
||||
if (!$this->has($key)) {
|
||||
return $default;
|
||||
}
|
||||
return $this->lists[$key];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
* @return mixed
|
||||
*/
|
||||
#[Pure] public function offsetGet(mixed $offset): mixed
|
||||
{
|
||||
return $this->get($offset);
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
*/
|
||||
public function del(string $key): void
|
||||
{
|
||||
if (!$this->has($key)) {
|
||||
return;
|
||||
}
|
||||
unset($this->lists[$key]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
* @param mixed $value
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetSet(mixed $offset, mixed $value)
|
||||
{
|
||||
$this->put($offset, $value);
|
||||
}
|
||||
/**
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $key): bool
|
||||
{
|
||||
return array_key_exists($key, $this->lists);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetUnset(mixed $offset)
|
||||
{
|
||||
unset($this->lists[$offset]);
|
||||
}
|
||||
/**
|
||||
* @param mixed $offset
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
return isset($this->lists[$offset]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
* @return mixed
|
||||
*/
|
||||
#[Pure] public function offsetGet(mixed $offset): mixed
|
||||
{
|
||||
return $this->get($offset);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
* @param mixed $value
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
{
|
||||
$this->put($offset, $value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
*/
|
||||
#[ReturnTypeWillChange]
|
||||
public function offsetUnset(mixed $offset): void
|
||||
{
|
||||
unset($this->lists[$offset]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param HashMap $root
|
||||
* @param string $leaf
|
||||
* @return HashMap
|
||||
*/
|
||||
public static function Tree(HashMap $root, string $leaf): HashMap
|
||||
{
|
||||
if ($root->has($leaf)) {
|
||||
$hashMap = $root->get($leaf);
|
||||
} else {
|
||||
$hashMap = new HashMap();
|
||||
$root->put($leaf, $hashMap);
|
||||
}
|
||||
return $hashMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+291
-185
@@ -6,6 +6,8 @@ namespace Kiri\Core;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Swift_Message;
|
||||
use Swift_SmtpTransport;
|
||||
|
||||
|
||||
/**
|
||||
@@ -15,205 +17,309 @@ use Exception;
|
||||
class Help
|
||||
{
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public static function toXml(array $data): string
|
||||
{
|
||||
$xml = "<xml>";
|
||||
foreach ($data as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
$xml .= "<" . $key . ">" . static::xmlChild($val) . "</" . $key . ">";
|
||||
} else if (is_numeric($val)) {
|
||||
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
|
||||
} else {
|
||||
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
|
||||
}
|
||||
}
|
||||
$xml .= "</xml>";
|
||||
return $xml;
|
||||
}
|
||||
/**
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public static function toXml(array $data): string
|
||||
{
|
||||
$xml = "<xml>";
|
||||
foreach ($data as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
$xml .= "<" . $key . ">" . static::xmlChild($val) . "</" . $key . ">";
|
||||
} else if (is_numeric($val)) {
|
||||
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
|
||||
} else {
|
||||
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
|
||||
}
|
||||
}
|
||||
$xml .= "</xml>";
|
||||
return $xml;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
* @return string
|
||||
*/
|
||||
private static function xmlChild(array $array): string
|
||||
{
|
||||
$string = '';
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$string .= static::xmlChild($value);
|
||||
} else if (is_numeric($value)) {
|
||||
$string .= "<" . $key . ">" . $value . "</" . $key . ">";
|
||||
} else {
|
||||
$string .= "<" . $key . "><![CDATA[" . $value . "]]></" . $key . ">";
|
||||
}
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
/**
|
||||
* @param array $array
|
||||
* @return string
|
||||
*/
|
||||
private static function xmlChild(array $array): string
|
||||
{
|
||||
$string = '';
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$string .= static::xmlChild($value);
|
||||
} else if (is_numeric($value)) {
|
||||
$string .= "<" . $key . ">" . $value . "</" . $key . ">";
|
||||
} else {
|
||||
$string .= "<" . $key . "><![CDATA[" . $value . "]]></" . $key . ">";
|
||||
}
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $xml
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function toArray($xml): mixed
|
||||
{
|
||||
if (empty($xml)) {
|
||||
return [];
|
||||
} else if (is_array($xml)) {
|
||||
return $xml;
|
||||
}
|
||||
if (!($_xml = Xml::isXml($xml))) {
|
||||
return static::jsonToArray($xml);
|
||||
}
|
||||
return $_xml;
|
||||
}
|
||||
/**
|
||||
* @param $xml
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public static function toArray($xml): mixed
|
||||
{
|
||||
if (empty($xml)) {
|
||||
return [];
|
||||
} else if (is_array($xml)) {
|
||||
return $xml;
|
||||
}
|
||||
if (!($_xml = Xml::isXml($xml))) {
|
||||
return static::jsonToArray($xml);
|
||||
}
|
||||
return $_xml;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $xml
|
||||
* @return mixed
|
||||
*/
|
||||
public static function jsonToArray($xml): mixed
|
||||
{
|
||||
$_xml = json_decode($xml, true);
|
||||
if (is_null($_xml)) {
|
||||
return [];
|
||||
}
|
||||
return $_xml;
|
||||
}
|
||||
/**
|
||||
* @param $xml
|
||||
* @return mixed
|
||||
*/
|
||||
public static function jsonToArray($xml): mixed
|
||||
{
|
||||
$_xml = json_decode($xml, true);
|
||||
if (is_null($_xml)) {
|
||||
return [];
|
||||
}
|
||||
return $_xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $xml
|
||||
* @return mixed
|
||||
*/
|
||||
public static function xmlToArray($xml): mixed
|
||||
{
|
||||
if (is_array($xml)) {
|
||||
return $xml;
|
||||
}
|
||||
if (($data = @simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)) !== false) {
|
||||
return json_decode(json_encode($data), TRUE);
|
||||
}
|
||||
if (!is_null($json = json_decode($xml, TRUE))) {
|
||||
return $json;
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
/**
|
||||
* @param $xml
|
||||
* @return mixed
|
||||
*/
|
||||
public static function xmlToArray($xml): mixed
|
||||
{
|
||||
if (is_array($xml)) {
|
||||
return $xml;
|
||||
}
|
||||
if (($data = @simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)) !== false) {
|
||||
return json_decode(json_encode($data), TRUE);
|
||||
}
|
||||
if (!is_null($json = json_decode($xml, TRUE))) {
|
||||
return $json;
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $parameter
|
||||
* @return array|false|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function toString($parameter): bool|array|string
|
||||
{
|
||||
if (!is_string($parameter)) {
|
||||
$parameter = ArrayAccess::toArray($parameter);
|
||||
if (is_array($parameter)) {
|
||||
$parameter = Json::encode($parameter);
|
||||
}
|
||||
}
|
||||
return $parameter;
|
||||
}
|
||||
/**
|
||||
* @param $parameter
|
||||
* @return array|false|string
|
||||
* @throws
|
||||
*/
|
||||
public static function toString($parameter): bool|array|string
|
||||
{
|
||||
if (!is_string($parameter)) {
|
||||
$parameter = Json::encode(ArrayAccess::toArray($parameter));
|
||||
}
|
||||
return $parameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $json
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function toJson(mixed $json): bool|string
|
||||
{
|
||||
if (is_object($json)) {
|
||||
$json = get_object_vars($json);
|
||||
}
|
||||
if (is_array($json)) {
|
||||
return json_encode($json, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
$matchQuote = '/(<\?xml.*?\?>)?<([a-zA-Z_]+)>(<([a-zA-Z_]+)><!.*?><\/\4>)+<\/\2>/';
|
||||
if (preg_match($matchQuote, $json)) {
|
||||
$json = self::xmlToArray($json);
|
||||
} else {
|
||||
$json = json_decode($json, true);
|
||||
}
|
||||
if (!is_array($json)) {
|
||||
$json = [];
|
||||
}
|
||||
return json_encode($json, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
/**
|
||||
* @param mixed $json
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function toJson(mixed $json): bool|string
|
||||
{
|
||||
if (is_object($json)) {
|
||||
$json = get_object_vars($json);
|
||||
}
|
||||
if (is_array($json)) {
|
||||
return json_encode($json, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
$matchQuote = '/(<\?xml.*?\?>)?<([a-zA-Z_]+)>(<([a-zA-Z_]+)><!.*?><\/\4>)+<\/\2>/';
|
||||
if (preg_match($matchQuote, $json)) {
|
||||
$json = self::xmlToArray($json);
|
||||
} else {
|
||||
$json = json_decode($json, true);
|
||||
}
|
||||
if (!is_array($json)) {
|
||||
$json = [];
|
||||
}
|
||||
return json_encode($json, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $length
|
||||
* @return string
|
||||
*
|
||||
* 随机字符串
|
||||
*/
|
||||
public static function random($length = 20): string
|
||||
{
|
||||
$res = [];
|
||||
$str = 'abcdefghijklmnopqrstuvwxyz';
|
||||
$str .= strtoupper($str) . '1234567890';
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$rand = substr($str, rand(0, strlen($str) - 2), 1);
|
||||
if (empty($rand)) {
|
||||
$rand = substr($str, strlen($str) - 3, 1);
|
||||
}
|
||||
array_push($res, $rand);
|
||||
}
|
||||
/**
|
||||
* @param int $length
|
||||
* @return string
|
||||
*
|
||||
* 随机字符串
|
||||
*/
|
||||
public static function random(int $length = 20): string
|
||||
{
|
||||
$res = [];
|
||||
$str = 'abcdefghijklmnopqrstuvwxyz';
|
||||
$str .= strtoupper($str) . '1234567890';
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$rand = substr($str, rand(0, strlen($str) - 2), 1);
|
||||
if (empty($rand)) {
|
||||
$rand = substr($str, strlen($str) - 3, 1);
|
||||
}
|
||||
$res[] = $rand;
|
||||
}
|
||||
|
||||
return implode($res);
|
||||
}
|
||||
return implode($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
* @param $key
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public static function sign(array $array, $key, string $type = 'MD5'): string
|
||||
{
|
||||
ksort($array, SORT_ASC);
|
||||
$string = [];
|
||||
foreach ($array as $hashKey => $val) {
|
||||
if (empty($val)) {
|
||||
continue;
|
||||
}
|
||||
$string[] = $hashKey . '=' . $val;
|
||||
}
|
||||
$string[] = 'key=' . $key;
|
||||
$string = implode('&', $string);
|
||||
if ($type == 'MD5') {
|
||||
return strtoupper(md5($string));
|
||||
} else {
|
||||
return hash('sha256', $string);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param array $array
|
||||
* @param $key
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public static function sign(array $array, $key, string $type = 'MD5'): string
|
||||
{
|
||||
ksort($array, SORT_ASC);
|
||||
$string = [];
|
||||
foreach ($array as $hashKey => $val) {
|
||||
if (empty($val)) {
|
||||
continue;
|
||||
}
|
||||
$string[] = $hashKey . '=' . $val;
|
||||
}
|
||||
$string[] = 'key=' . $key;
|
||||
$string = implode('&', $string);
|
||||
if ($type == 'MD5') {
|
||||
return strtoupper(md5($string));
|
||||
} else {
|
||||
return hash('sha256', $string);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $email
|
||||
* @param string $Subject
|
||||
* @param $messageContent
|
||||
*/
|
||||
public static function sendEmail($email, string $Subject, $messageContent)
|
||||
{
|
||||
if (!class_exists('\Swift_Mailer')) {
|
||||
return;
|
||||
}
|
||||
$mailer = new \Swift_Mailer((new \Swift_SmtpTransport($email['host'], $email['port']))
|
||||
->setUsername($email['username'])->setPassword($email['password']));
|
||||
$message = (new \Swift_Message($Subject))
|
||||
->setFrom([$email['send']['address'] => $email['send']['nickname']])
|
||||
->setBody('Here is the message itself');
|
||||
/**
|
||||
* @param $email
|
||||
* @param string $Subject
|
||||
* @param $messageContent
|
||||
*/
|
||||
public static function sendEmail($email, string $Subject, $messageContent): void
|
||||
{
|
||||
if (!class_exists('\Swift_Mailer')) {
|
||||
return;
|
||||
}
|
||||
$mailer = new \Swift_Mailer((new Swift_SmtpTransport($email['host'], $email['port']))
|
||||
->setUsername($email['username'])->setPassword($email['password']));
|
||||
$message = (new Swift_Message($Subject))
|
||||
->setFrom([$email['send']['address'] => $email['send']['nickname']])
|
||||
->setBody('Here is the message itself');
|
||||
|
||||
foreach ($email['receive'] as $item) {
|
||||
$message->setTo([$item['address'], $item['address'] => $item['nickname']]);
|
||||
}
|
||||
$mailer->send($messageContent);
|
||||
}
|
||||
foreach ($email['receive'] as $item) {
|
||||
$message->setTo([$item['address'], $item['address'] => $item['nickname']]);
|
||||
}
|
||||
$mailer->send($messageContent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $year
|
||||
* @return int
|
||||
*/
|
||||
public static function age(int $year): int
|
||||
{
|
||||
return date('Y') - $year;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $year
|
||||
* @return string
|
||||
*/
|
||||
public static function zodiac(int $year): string
|
||||
{
|
||||
$zodiac = "-1";
|
||||
$start = 1901;
|
||||
$x = ($start - $year) % 12;
|
||||
if ($x == 1 || $x == -11) {
|
||||
$zodiac = "鼠";
|
||||
}
|
||||
if ($x == 0) {
|
||||
$zodiac = "牛";
|
||||
}
|
||||
if ($x == 11 || $x == -1) {
|
||||
$zodiac = "虎";
|
||||
}
|
||||
if ($x == 10 || $x == -2) {
|
||||
$zodiac = "兔";
|
||||
}
|
||||
if ($x == 9 || $x == -3) {
|
||||
$zodiac = "龙";
|
||||
}
|
||||
if ($x == 8 || $x == -4) {
|
||||
$zodiac = "蛇";
|
||||
}
|
||||
if ($x == 7 || $x == -5) {
|
||||
$zodiac = "马";
|
||||
}
|
||||
if ($x == 6 || $x == -6) {
|
||||
$zodiac = "羊";
|
||||
}
|
||||
if ($x == 5 || $x == -7) {
|
||||
$zodiac = "猴";
|
||||
}
|
||||
if ($x == 4 || $x == -8) {
|
||||
$zodiac = "鸡";
|
||||
}
|
||||
if ($x == 3 || $x == -9) {
|
||||
$zodiac = "狗";
|
||||
}
|
||||
if ($x == 2 || $x == -10) {
|
||||
$zodiac = "猪";
|
||||
}
|
||||
return $zodiac;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $month
|
||||
* @param int $day
|
||||
* @return string
|
||||
*/
|
||||
public static function constellation(int $month, int $day): string
|
||||
{
|
||||
$star = "-1";
|
||||
if (($month == 1 && $day >= 20) || ($month == 2 && $day <= 18)) {
|
||||
$star = "水瓶座";
|
||||
}
|
||||
if (($month == 2 && $day >= 19) || ($month == 3 && $day <= 20)) {
|
||||
$star = "双鱼座";
|
||||
}
|
||||
if (($month == 3 && $day >= 21) || ($month == 4 && $day <= 19)) {
|
||||
$star = "白羊座";
|
||||
}
|
||||
if (($month == 4 && $day >= 20) || ($month == 5 && $day <= 20)) {
|
||||
$star = "金牛座";
|
||||
}
|
||||
if (($month == 5 && $day >= 21) || ($month == 6 && $day <= 21)) {
|
||||
$star = "双子座";
|
||||
}
|
||||
if (($month == 6 && $day >= 22) || ($month == 7 && $day <= 22)) {
|
||||
$star = "巨蟹座";
|
||||
}
|
||||
if (($month == 7 && $day >= 23) || ($month == 8 && $day <= 22)) {
|
||||
$star = "狮子座";
|
||||
}
|
||||
if (($month == 8 && $day >= 23) || ($month == 9 && $day <= 22)) {
|
||||
$star = "处女座";
|
||||
}
|
||||
if (($month == 9 && $day >= 23) || ($month == 10 && $day <= 22)) {
|
||||
$star = "天秤座";
|
||||
}
|
||||
if (($month == 10 && $day >= 23) || ($month == 11 && $day <= 21)) {
|
||||
$star = "天蝎座";
|
||||
}
|
||||
if (($month == 11 && $day >= 22) || ($month == 12 && $day <= 21)) {
|
||||
$star = "射手座";
|
||||
}
|
||||
if (($month == 12 && $day >= 22) || ($month == 1 && $day <= 19)) {
|
||||
$star = "魔蝎座";
|
||||
}
|
||||
return $star;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+110
-87
@@ -22,100 +22,123 @@ class Json
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return false|string
|
||||
*/
|
||||
public static function encode($data): bool|string
|
||||
{
|
||||
if (empty($data)) {
|
||||
return false;
|
||||
}
|
||||
if (is_array($data)) {
|
||||
return json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
/**
|
||||
* @param $data
|
||||
* @return false|string
|
||||
*/
|
||||
public static function encode($data): bool|string
|
||||
{
|
||||
if (empty($data)) {
|
||||
return false;
|
||||
}
|
||||
if (is_array($data)) {
|
||||
return json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @param bool $asArray
|
||||
* @return mixed
|
||||
*/
|
||||
public static function decode($data, bool $asArray = true): mixed
|
||||
{
|
||||
if (is_array($data) || is_numeric($data)) {
|
||||
return $data;
|
||||
}
|
||||
if (!is_string($data)) return null;
|
||||
return json_decode($data, $asArray);
|
||||
}
|
||||
/**
|
||||
* @param $data
|
||||
* @param bool $asArray
|
||||
* @return mixed
|
||||
*/
|
||||
public static function decode($data, bool $asArray = true): mixed
|
||||
{
|
||||
if (is_array($data) || is_numeric($data)) {
|
||||
return $data;
|
||||
}
|
||||
if (!is_string($data)) return null;
|
||||
return json_decode($data, $asArray);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $code
|
||||
* @param string|array $message
|
||||
* @param array|int $data
|
||||
* @param int $count
|
||||
* @param array $exPageInfo
|
||||
* @return string|bool
|
||||
*/
|
||||
public static function to($code, string|array $message = '', array|int $data = [], int $count = 0, array $exPageInfo = []): string|bool
|
||||
{
|
||||
$params['code'] = $code;
|
||||
if (!is_string($message)) {
|
||||
$params['message'] = 'System success.';
|
||||
$params['param'] = $message;
|
||||
if (!empty($data)) {
|
||||
$params['exPageInfo'] = $data;
|
||||
}
|
||||
} else {
|
||||
$params['message'] = $message;
|
||||
$params['param'] = $data;
|
||||
}
|
||||
if (!empty($exPageInfo)) {
|
||||
$params['exPageInfo'] = $exPageInfo;
|
||||
}
|
||||
$params['count'] = $count;
|
||||
if (is_numeric($data) || !is_numeric($count)) {
|
||||
$params['count'] = $data;
|
||||
$params['exPageInfo'] = $count;
|
||||
}
|
||||
if ((int)$params['count'] == -100) {
|
||||
$params['count'] = 1;
|
||||
}
|
||||
return static::encode($params);
|
||||
}
|
||||
/**
|
||||
* @param string $message
|
||||
* @param int $code
|
||||
* @param array|string $data
|
||||
* @param int $count
|
||||
* @return string
|
||||
*/
|
||||
public static function jsonFail(string $message, int $code = 500, array|string $data = [], int $count = 0): string
|
||||
{
|
||||
return json_encode(['code' => $code, 'param' => $data, 'message' => $message, 'count' => $count], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Throwable|Error $throwable
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function error(Throwable|Error $throwable): bool|string
|
||||
{
|
||||
$array['code'] = $throwable->getCode() == 0 ? 500 : $throwable->getCode();
|
||||
$array['message'] = $throwable->getMessage();
|
||||
$array['param'] = [
|
||||
'file' => $throwable->getFile(),
|
||||
'line' => $throwable->getLine()
|
||||
];
|
||||
return Json::encode($array);
|
||||
}
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array|string $data
|
||||
* @param int $count
|
||||
* @return string
|
||||
*/
|
||||
public static function jsonSuccess(array|string $data = [], string $message = "ok", int $count = 0): string
|
||||
{
|
||||
return json_encode(['code' => 0, 'param' => $data, 'message' => $message, 'count' => $count], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $state
|
||||
* @param $body
|
||||
* @return false|int|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function output($state, $body): bool|int|string
|
||||
{
|
||||
$params['state'] = $state;
|
||||
$params['body'] = ArrayAccess::toArray($body);
|
||||
/**
|
||||
* @param $code
|
||||
* @param string|array $message
|
||||
* @param array|int $data
|
||||
* @param int $count
|
||||
* @param array $exPageInfo
|
||||
* @return string|bool
|
||||
*/
|
||||
public static function to($code, string|array $message = '', array|int $data = [], int $count = 0, array $exPageInfo = []): string|bool
|
||||
{
|
||||
$params['code'] = $code;
|
||||
if (!is_string($message)) {
|
||||
$params['message'] = 'System success.';
|
||||
$params['param'] = $message;
|
||||
$params['exPageInfo'] = $data;
|
||||
} else {
|
||||
$params['message'] = $message;
|
||||
$params['param'] = $data;
|
||||
}
|
||||
if (!empty($exPageInfo)) {
|
||||
$params['exPageInfo'] = $exPageInfo;
|
||||
}
|
||||
$params['count'] = $count;
|
||||
if (is_numeric($data) || !is_numeric($count)) {
|
||||
$params['count'] = $data;
|
||||
$params['exPageInfo'] = $count;
|
||||
}
|
||||
if ((int)$params['count'] == -100) {
|
||||
$params['count'] = 1;
|
||||
}
|
||||
return static::encode($params);
|
||||
}
|
||||
|
||||
return static::encode($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Throwable|Error $throwable
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function error(Throwable|Error $throwable): bool|string
|
||||
{
|
||||
$array['code'] = $throwable->getCode() == 0 ? 500 : $throwable->getCode();
|
||||
$array['message'] = $throwable->getMessage();
|
||||
$array['param'] = [
|
||||
'file' => $throwable->getFile(),
|
||||
'line' => $throwable->getLine()
|
||||
];
|
||||
return Json::encode($array);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $state
|
||||
* @param $body
|
||||
* @return false|int|string
|
||||
* @throws
|
||||
*/
|
||||
public static function output($state, $body): bool|int|string
|
||||
{
|
||||
$params['state'] = $state;
|
||||
$params['body'] = ArrayAccess::toArray($body);
|
||||
|
||||
return static::encode($params);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-19
@@ -14,9 +14,9 @@ use Exception;
|
||||
class Str
|
||||
{
|
||||
|
||||
const STRING = 'abcdefghijklmnopqrstuvwxyz';
|
||||
const string STRING = 'abcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
const NUMBER = '01234567890';
|
||||
const string NUMBER = '01234567890';
|
||||
|
||||
/**
|
||||
* @param int $length
|
||||
@@ -45,7 +45,7 @@ class Str
|
||||
*/
|
||||
public static function random(int $length = 20): int|string
|
||||
{
|
||||
$number = '';
|
||||
$number = '';
|
||||
$default = str_split(self::NUMBER);
|
||||
if ($length < 1) $length = 1;
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
@@ -107,7 +107,7 @@ class Str
|
||||
*/
|
||||
public static function isSerialize($data, $callBack = NULL): bool
|
||||
{
|
||||
$false = !empty($data) && swoole_unserialize($data) !== FALSE;
|
||||
$false = !empty($data) && unserialize($data) !== FALSE;
|
||||
if ($false && is_callable($callBack, TRUE)) {
|
||||
return call_user_func($callBack, $data);
|
||||
}
|
||||
@@ -151,13 +151,13 @@ class Str
|
||||
{
|
||||
$res = [];
|
||||
$add = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
$len = strlen($key) < 0 ? 1 : (strlen($key) + 5 > strlen($add) ? strlen($add) - 5 : strlen($key));
|
||||
$len = strlen($key) + 5 > strlen($add) ? strlen($add) - 5 : strlen($key);
|
||||
if ($number < 1) $number = 10;
|
||||
$array = str_split($str);
|
||||
asort($array);
|
||||
$str = implode('', $array);
|
||||
for ($i = 0; $i < $number; $i++) {
|
||||
$_tmp = md5($key) . md5($str) . mb_substr($add, $len, $len + 5, 'utf-8');
|
||||
$_tmp = md5($key) . md5($str) . mb_substr($add, $len, $len + 5, 'utf-8');
|
||||
$res[] = md5($_tmp);
|
||||
}
|
||||
sort($res, SORT_STRING);
|
||||
@@ -171,17 +171,12 @@ class Str
|
||||
*/
|
||||
public static function filename($file, $type): string
|
||||
{
|
||||
switch ($type) {
|
||||
case 'image/png':
|
||||
return md5_file($file) . '.png';
|
||||
case 'image/jpeg':
|
||||
case 'image/jpg':
|
||||
return md5_file($file) . '.jpg';
|
||||
case 'image/gif':
|
||||
return md5_file($file) . '.gif';
|
||||
break;
|
||||
}
|
||||
return md5_file($file);
|
||||
return match ($type) {
|
||||
'image/png' => md5_file($file) . '.png',
|
||||
'image/jpeg', 'image/jpg' => md5_file($file) . '.jpg',
|
||||
'image/gif' => md5_file($file) . '.gif',
|
||||
default => md5_file($file),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,8 +227,8 @@ class Str
|
||||
*/
|
||||
public static function clear(string $string): array|string|null
|
||||
{
|
||||
$char = '。、!?:;﹑•"…‘’“”〝〞∕¦‖— 〈〉﹞﹝「」‹›〖〗】【»«』『〕〔》《﹐¸﹕︰﹔!¡?¿﹖﹌﹏﹋'´ˊˋ―﹫︳︴¯_ ̄﹢﹦﹤‐˜﹟﹩﹠﹪﹡﹨﹍﹉﹎﹊ˇ︵︶︷︸︹︿﹀︺︽︾ˉ﹁﹂﹃﹄︻︼()';
|
||||
return preg_replace(["/[[:punct:]]/i", '/[' . $char . ']/u', '/[ ]{2,}/'], '', $string);
|
||||
$char = '。、!?:;﹑•"…‘’“”〝〞∕¦‖— 〈〉﹞﹝「」‹›〖〗】【»«』『〕〔》《﹐¸﹕︰﹔¡¿﹖﹌﹏﹋'´ˊˋ―﹫︳︴¯_ ̄﹢﹦﹤‐˜﹟﹩﹠﹪﹡﹨﹍﹉﹎﹊ˇ︵︶︷︸︹︿﹀︺︽︾ˉ﹁﹂﹃﹄︻︼()';
|
||||
return preg_replace(["/[[:punct:]]/i", '/[' . $char . ']/u', '/ {2,}/'], '', $string);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+34
-34
@@ -18,40 +18,40 @@ use Exception;
|
||||
class Xml
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @param bool $asArray
|
||||
* @return array|object
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function toArray($data, bool $asArray = true): object|array
|
||||
{
|
||||
$data = simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||
if ($data === false) {
|
||||
throw new Exception('Parameter format error.');
|
||||
}
|
||||
$array = get_object_vars($data);
|
||||
if (isset($array[0])) {
|
||||
$array[$data->getName()] = $array[0];
|
||||
unset($array[0]);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
/**
|
||||
* @param $data
|
||||
* @param bool $asArray
|
||||
* @return array|object
|
||||
* @throws
|
||||
*/
|
||||
public static function toArray($data, bool $asArray = true): object|array
|
||||
{
|
||||
$data = \simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||
if ($data === false) {
|
||||
throw new Exception('Parameter format error.');
|
||||
}
|
||||
$array = \get_object_vars($data);
|
||||
if (isset($array[0])) {
|
||||
$array[$data->getName()] = $array[0];
|
||||
unset($array[0]);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $str
|
||||
* @return array|bool|object
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function isXml($str): object|bool|array
|
||||
{
|
||||
$xml_parser = xml_parser_create();
|
||||
if (!xml_parse($xml_parser, $str, true)) {
|
||||
xml_parser_free($xml_parser);
|
||||
return false;
|
||||
} else {
|
||||
return self::toArray($str);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param $str
|
||||
* @return array|bool|object
|
||||
* @throws
|
||||
*/
|
||||
public static function isXml($str): object|bool|array
|
||||
{
|
||||
$xml_parser = \xml_parser_create();
|
||||
if (!\xml_parse($xml_parser, $str, true)) {
|
||||
\xml_parser_free($xml_parser);
|
||||
return false;
|
||||
} else {
|
||||
return self::toArray($str);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,454 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/24 0024
|
||||
* Time: 17:27
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Di;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Kiri;
|
||||
use Kiri\Abstracts\Logger;
|
||||
use Kiri\Annotation\Inject;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use ReflectionFunction;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
|
||||
/**
|
||||
* Class Container
|
||||
* @package Kiri\Di
|
||||
*/
|
||||
class Container implements ContainerInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* instance class by className
|
||||
*/
|
||||
private array $_singletons = [];
|
||||
|
||||
/**
|
||||
* @var ReflectionMethod[]
|
||||
*
|
||||
* class new instance construct parameter
|
||||
*/
|
||||
private array $_constructs = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* implements \ReflectClass
|
||||
*/
|
||||
private array $_reflection = [];
|
||||
|
||||
|
||||
/** @var array */
|
||||
private array $_parameters = [];
|
||||
|
||||
|
||||
/** @var array|string[] */
|
||||
private array $_interfaces = [
|
||||
LoggerInterface::class => Logger::class
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function get(string $id): mixed
|
||||
{
|
||||
if ($id == ContainerInterface::class) {
|
||||
return $this;
|
||||
}
|
||||
return $this->make($id, [], []);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param array $constrict
|
||||
* @param array $config
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function make($class, array $constrict = [], array $config = []): mixed
|
||||
{
|
||||
if ($class == ContainerInterface::class) {
|
||||
return $this;
|
||||
}
|
||||
if ($this->isInterface($class)) {
|
||||
$class = $this->_interfaces[$class];
|
||||
}
|
||||
if (!isset($this->_singletons[$class])) {
|
||||
$this->_singletons[$class] = $this->resolve($class, $constrict, $config);
|
||||
}
|
||||
return $this->_singletons[$class];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $interface
|
||||
* @param string $class
|
||||
*/
|
||||
public function mapping(string $interface, string $class)
|
||||
{
|
||||
$this->_interfaces[$interface] = $class;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @return bool
|
||||
*/
|
||||
public function isInterface($class): bool
|
||||
{
|
||||
$reflect = $this->getReflect($class);
|
||||
if ($reflect->isInterface()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $interface
|
||||
* @param $object
|
||||
*/
|
||||
public function setBindings(string $interface, $object)
|
||||
{
|
||||
if (is_string($object)) {
|
||||
$this->_interfaces[$interface] = $object;
|
||||
} else {
|
||||
$className = get_class($object);
|
||||
$this->_interfaces[$interface] = $className;
|
||||
$this->_singletons[$className] = $object;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param array $constrict
|
||||
* @param array $config
|
||||
* @return object
|
||||
* @throws
|
||||
*/
|
||||
public function create($class, array $constrict = [], array $config = []): object
|
||||
{
|
||||
return $this->resolve($class, $constrict, $config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $constrict
|
||||
* @param $config
|
||||
*
|
||||
* @return object
|
||||
* @throws Exception
|
||||
*/
|
||||
private function resolve($class, $constrict, $config): object
|
||||
{
|
||||
$reflect = $this->resolveDependencies($class);
|
||||
if (!$reflect->isInstantiable()) {
|
||||
throw new ReflectionException('Class ' . $class . ' cannot be instantiated');
|
||||
}
|
||||
|
||||
$object = $this->newInstance($reflect, $constrict);
|
||||
|
||||
$this->propertyInject($reflect, $object);
|
||||
|
||||
return $this->onAfterInit($object, $config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $reflect
|
||||
* @param $dependencies
|
||||
* @return object
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
private function newInstance(ReflectionClass $reflect, $dependencies): object
|
||||
{
|
||||
if (!isset($this->_constructs[$reflect->getName()])) {
|
||||
return $reflect->newInstance();
|
||||
}
|
||||
$construct = $this->_constructs[$reflect->getName()];
|
||||
if ($construct->getNumberOfParameters() < 1) {
|
||||
return $reflect->newInstance();
|
||||
}
|
||||
$parameters = $this->mergeParam($this->resolveMethodParameters($construct), $dependencies);
|
||||
return $reflect->newInstanceArgs($parameters);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $reflect
|
||||
* @param $object
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function propertyInject(ReflectionClass $reflect, $object): mixed
|
||||
{
|
||||
foreach (NoteManager::getPropertyAnnotation($reflect) as $property => $inject) {
|
||||
/** @var Inject $inject */
|
||||
$inject->execute($object, $property);
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $className
|
||||
* @param $method
|
||||
* @return array
|
||||
*/
|
||||
public function getMethodAttribute($className, $method = null): array
|
||||
{
|
||||
$methods = NoteManager::getMethodAnnotation($this->getReflect($className));
|
||||
if (!empty($method)) {
|
||||
return $methods[$method] ?? [];
|
||||
}
|
||||
return $methods;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string|null $property
|
||||
* @return ReflectionProperty|ReflectionProperty[]|null
|
||||
*/
|
||||
public function getClassReflectionProperty(string $class, string $property = null): ReflectionProperty|null|array
|
||||
{
|
||||
$lists = NoteManager::getProperty($this->getReflect($class));
|
||||
if (empty($lists)) {
|
||||
return null;
|
||||
}
|
||||
if (!empty($property)) {
|
||||
return $lists[$property] ?? null;
|
||||
}
|
||||
return $lists;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $object
|
||||
* @param $config
|
||||
* @return mixed
|
||||
*/
|
||||
private function onAfterInit($object, $config): mixed
|
||||
{
|
||||
Kiri::configure($object, $config);
|
||||
if (method_exists($object, 'init') && is_callable([$object, 'init'])) {
|
||||
call_user_func([$object, 'init']);
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @return ReflectionClass
|
||||
*/
|
||||
private function resolveDependencies($class): ReflectionClass
|
||||
{
|
||||
if (isset($this->_reflection[$class])) {
|
||||
return $this->_reflection[$class];
|
||||
}
|
||||
$reflect = new ReflectionClass($class);
|
||||
if ($reflect->isAbstract() || $reflect->isTrait() || $reflect->isInterface()) {
|
||||
return $this->_reflection[$class] = $reflect;
|
||||
}
|
||||
$construct = NoteManager::resolveTarget($reflect);
|
||||
if (!empty($construct) && $construct->getNumberOfParameters() > 0) {
|
||||
$this->_constructs[$class] = $construct;
|
||||
}
|
||||
return $this->_reflection[$class] = $reflect;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass|string $class
|
||||
* @return ReflectionMethod[]
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function getReflectMethods(ReflectionClass|string $class): array
|
||||
{
|
||||
if (is_string($class)) {
|
||||
$class = $this->getReflect($class);
|
||||
}
|
||||
return NoteManager::getMethods($class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass|string $class
|
||||
* @param string $method
|
||||
* @return ReflectionMethod|null
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function getReflectMethod(ReflectionClass|string $class, string $method): ?ReflectionMethod
|
||||
{
|
||||
return $this->getReflectMethods($class)[$method] ?? null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param string $method
|
||||
* @return array|null
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function getMethodParameters(string $className, string $method): ?array
|
||||
{
|
||||
if (isset($this->_parameters[$className]) && isset($this->_parameters[$className][$method])) {
|
||||
return $this->_parameters[$className][$method];
|
||||
}
|
||||
$reflectMethod = $this->getReflectMethod($this->getReflect($className), $method);
|
||||
if (!($reflectMethod instanceof ReflectionMethod)) {
|
||||
throw new ReflectionException("Class does not have a function $className::$method");
|
||||
}
|
||||
$className = $reflectMethod->getDeclaringClass()->getName();
|
||||
if (isset($this->_parameters[$className]) && isset($this->_parameters[$className][$reflectMethod->getName()])) {
|
||||
return $this->_parameters[$className][$reflectMethod->getName()];
|
||||
}
|
||||
return $this->setParameters($className, $reflectMethod->getName(), $this->resolveMethodParameters($reflectMethod));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @param $method
|
||||
* @param $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
private function setParameters($class, $method, $parameters): mixed
|
||||
{
|
||||
if (!isset($this->_parameters[$class])) {
|
||||
$this->_parameters[$class] = [];
|
||||
}
|
||||
return $this->_parameters[$class][$method] = $parameters;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Closure $reflectionMethod
|
||||
* @return array
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function getFunctionParameters(Closure $reflectionMethod): array
|
||||
{
|
||||
return $this->resolveMethodParameters(new ReflectionFunction($reflectionMethod));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionMethod|ReflectionFunction $reflectionMethod
|
||||
* @return array
|
||||
*/
|
||||
private function resolveMethodParameters(ReflectionMethod|ReflectionFunction $reflectionMethod): array
|
||||
{
|
||||
if ($reflectionMethod->getNumberOfParameters() < 1) {
|
||||
return [];
|
||||
}
|
||||
$params = [];
|
||||
foreach ($reflectionMethod->getParameters() as $key => $parameter) {
|
||||
if ($parameter->isDefaultValueAvailable()) {
|
||||
$params[$key] = $parameter->getDefaultValue();
|
||||
} else if ($parameter->getType() === null) {
|
||||
$params[$key] = $parameter->getType();
|
||||
} else {
|
||||
$type = $parameter->getType()->getName();
|
||||
if (is_string($type) && class_exists($type) || isset($this->_interfaces[$type])) {
|
||||
$type = Kiri::getDi()->get($type);
|
||||
}
|
||||
$params[$key] = match ($parameter->getType()) {
|
||||
'string' => '',
|
||||
'int', 'float' => 0,
|
||||
'', null, 'object', 'mixed' => NULL,
|
||||
'bool' => false,
|
||||
default => $type
|
||||
};
|
||||
}
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
* @return ReflectionClass|null
|
||||
*/
|
||||
public function getReflect($class): ?ReflectionClass
|
||||
{
|
||||
if (!isset($this->_reflection[$class])) {
|
||||
return $this->resolveDependencies($class);
|
||||
}
|
||||
return $this->_reflection[$class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $class
|
||||
*/
|
||||
public function unset($class)
|
||||
{
|
||||
if (is_array($class) && isset($class['class'])) {
|
||||
$class = $class['class'];
|
||||
} else if (is_object($class)) {
|
||||
$class = $class::class;
|
||||
}
|
||||
unset(
|
||||
$this->_reflection[$class], $this->_singletons[$class], $this->_constructs[$class]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function flush(): static
|
||||
{
|
||||
$this->_reflection = [];
|
||||
$this->_singletons = [];
|
||||
$this->_constructs = [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $old
|
||||
* @param $newParam
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function mergeParam($old, $newParam): array
|
||||
{
|
||||
if (empty($old)) {
|
||||
return $newParam;
|
||||
} else if (empty($newParam)) {
|
||||
return $old;
|
||||
}
|
||||
foreach ($newParam as $key => $val) {
|
||||
$old[$key] = $val;
|
||||
}
|
||||
return $old;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $id): bool
|
||||
{
|
||||
return isset($this->_singletons[$id]) || isset($this->_interfaces[$id]);
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Di;
|
||||
|
||||
use Kiri\Abstracts\Component;
|
||||
use Kiri;
|
||||
|
||||
|
||||
/**
|
||||
* 服务定位器
|
||||
*/
|
||||
class LocalService extends Component
|
||||
{
|
||||
|
||||
|
||||
private array $_components = [];
|
||||
|
||||
|
||||
private array $_definition = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $define
|
||||
*/
|
||||
public function set($name, $define)
|
||||
{
|
||||
unset($this->_components[$name]);
|
||||
|
||||
$this->_definition[$name] = $define;
|
||||
if (is_object($define) || $define instanceof \Closure) {
|
||||
$this->_components[$name] = $define;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function get(string $name, $throwException = true)
|
||||
{
|
||||
if (isset($this->_components[$name])) {
|
||||
return $this->_components[$name];
|
||||
}
|
||||
if (isset($this->_definition[$name])) {
|
||||
$definition = $this->_definition[$name];
|
||||
if (is_object($definition) && !$definition instanceof \Closure) {
|
||||
return $this->_components[$name] = $definition;
|
||||
}
|
||||
return $this->_components[$name] = Kiri::createObject($definition);
|
||||
} else if ($throwException) {
|
||||
throw new \Exception("Unknown component ID: $name");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $components
|
||||
*/
|
||||
public function setComponents(array $components)
|
||||
{
|
||||
foreach ($components as $name => $component) {
|
||||
$this->set($name, $component);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
public function has($id): bool
|
||||
{
|
||||
return isset($this->_components[$id]) || isset($this->_definition[$id]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
*/
|
||||
public function remove($id): void
|
||||
{
|
||||
unset($this->_components[$id], $this->_definition[$id]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,303 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Di;
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use ReflectionAttribute;
|
||||
use ReflectionClass;
|
||||
use ReflectionProperty;
|
||||
|
||||
class NoteManager
|
||||
{
|
||||
|
||||
|
||||
private static array $_classTarget = [];
|
||||
private static array $_classMethodAnnotation = [];
|
||||
private static array $_classMethod = [];
|
||||
private static array $_classPropertyAnnotation = [];
|
||||
private static array $_classProperty = [];
|
||||
private static array $_mapping = [];
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function clear()
|
||||
{
|
||||
static::$_classTarget = [];
|
||||
static::$_classMethodAnnotation = [];
|
||||
static::$_classMethod = [];
|
||||
static::$_classPropertyAnnotation = [];
|
||||
static::$_classProperty = [];
|
||||
static::$_mapping = [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
*/
|
||||
public static function setTargetAnnotation(ReflectionClass $class)
|
||||
{
|
||||
$className = $class->getName();
|
||||
if (!isset(static::$_classTarget[$className])) {
|
||||
static::$_classTarget[$className] = [];
|
||||
}
|
||||
foreach ($class->getAttributes() as $attribute) {
|
||||
if (!class_exists($attribute->getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$instance = $attribute->newInstance();
|
||||
|
||||
static::$_classTarget[$className][] = $instance;
|
||||
|
||||
self::setMappingClass($attribute, $className);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionAttribute $attribute
|
||||
* @param string $class
|
||||
*/
|
||||
public static function setMappingClass(ReflectionAttribute $attribute, string $class)
|
||||
{
|
||||
if (!isset(static::$_mapping[$attribute->getName()])) {
|
||||
static::$_mapping[$attribute->getName()] = [];
|
||||
}
|
||||
if (!isset(static::$_mapping[$attribute->getName()][$class])) {
|
||||
static::$_mapping[$attribute->getName()][$class] = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionAttribute $attribute
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
* @param mixed $instance
|
||||
*/
|
||||
public static function setMappingMethod(ReflectionAttribute $attribute, string $class, string $method, mixed $instance)
|
||||
{
|
||||
self::setMappingClass($attribute, $class);
|
||||
|
||||
if (!isset(static::$_mapping[$attribute->getName()][$class]['method'])) {
|
||||
static::$_mapping[$attribute->getName()][$class]['method'] = [];
|
||||
}
|
||||
static::$_mapping[$attribute->getName()][$class]['method'][] = [$method => $instance];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionAttribute $attribute
|
||||
* @param string $class
|
||||
* @param string $property
|
||||
* @param $instance
|
||||
*/
|
||||
public static function setMappingProperty(ReflectionAttribute $attribute, string $class, string $property, $instance)
|
||||
{
|
||||
self::setMappingClass($attribute, $class);
|
||||
|
||||
$mapping = static::$_mapping[$attribute->getName()][$class];
|
||||
if (!isset($mapping['property'])) {
|
||||
$mapping['property'] = [];
|
||||
}
|
||||
$mapping['property'][] = [$property => $instance];
|
||||
static::$_mapping[$attribute->getName()][$class] = $mapping;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $class
|
||||
* @return array
|
||||
*/
|
||||
public static function getTargetAnnotation(mixed $class): array
|
||||
{
|
||||
if (!is_string($class)) {
|
||||
$class = $class::class;
|
||||
}
|
||||
return static::$_classTarget[$class] ?? [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
*/
|
||||
public static function setMethodAnnotation(ReflectionClass $class)
|
||||
{
|
||||
$className = $class->getName();
|
||||
static::$_classMethodAnnotation[$className] = static::$_classMethod[$className] = [];
|
||||
foreach ($class->getMethods() as $ReflectionMethod) {
|
||||
static::$_classMethod[$className][$ReflectionMethod->getName()] = $ReflectionMethod;
|
||||
static::$_classMethodAnnotation[$className][$ReflectionMethod->getName()] = [];
|
||||
foreach ($ReflectionMethod->getAttributes() as $attribute) {
|
||||
if (!class_exists($attribute->getName())) {
|
||||
continue;
|
||||
}
|
||||
$instance = $attribute->newInstance();
|
||||
|
||||
static::$_classMethodAnnotation[$className][$ReflectionMethod->getName()][] = $instance;
|
||||
|
||||
self::setMappingMethod($attribute, $className, $ReflectionMethod->getName(), $instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasMethod(string $class, string $method): bool
|
||||
{
|
||||
return isset(static::$_classMethod[$class]) && isset(static::$_classMethod[$class][$method]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
* @return array
|
||||
*/
|
||||
#[Pure] public static function getMethodAnnotation(ReflectionClass $class): array
|
||||
{
|
||||
return static::$_classMethodAnnotation[$class->getName()] ?? [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \ReflectionClass $reflect
|
||||
* @return \ReflectionMethod|null
|
||||
*/
|
||||
public static function resolveTarget(ReflectionClass $reflect): ?\ReflectionMethod
|
||||
{
|
||||
NoteManager::setPropertyAnnotation($reflect);
|
||||
NoteManager::setTargetAnnotation($reflect);
|
||||
NoteManager::setMethodAnnotation($reflect);
|
||||
|
||||
return $reflect->getConstructor();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
*/
|
||||
public static function setPropertyAnnotation(ReflectionClass $class)
|
||||
{
|
||||
$className = $class->getName();
|
||||
static::$_classProperty[$className] = static::$_classPropertyAnnotation[$className] = [];
|
||||
foreach ($class->getProperties(ReflectionProperty::IS_PRIVATE | ReflectionProperty::IS_PUBLIC |
|
||||
ReflectionProperty::IS_PROTECTED) as $ReflectionMethod) {
|
||||
static::$_classProperty[$className][$ReflectionMethod->getName()] = $ReflectionMethod;
|
||||
foreach ($ReflectionMethod->getAttributes() as $attribute) {
|
||||
if (!class_exists($attribute->getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$instance = $attribute->newInstance();
|
||||
|
||||
static::$_classPropertyAnnotation[$className][$ReflectionMethod->getName()] = $instance;
|
||||
|
||||
self::setMappingProperty($attribute, $className, $ReflectionMethod->getName(), $instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param string|null $class
|
||||
* @return array[]
|
||||
*/
|
||||
public static function getAttributeTrees(string $attribute, string $class = null): array
|
||||
{
|
||||
$mapping = static::$_mapping[$attribute] ?? [];
|
||||
if (empty($mapping) || empty($class)) {
|
||||
return $mapping;
|
||||
}
|
||||
return $mapping[$class] ?? [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param string $class
|
||||
* @param string|null $method
|
||||
* @return array
|
||||
*/
|
||||
public static function getSpecify_annotation(string $attribute, string $class, string $method = null): mixed
|
||||
{
|
||||
$class = self::getAttributeTrees($attribute, $class);
|
||||
if (empty($class) || !isset($class['method'])) {
|
||||
return null;
|
||||
}
|
||||
if (empty($method)) {
|
||||
return $class['method'];
|
||||
}
|
||||
foreach ($class['method'] as $value) {
|
||||
$key = key($value);
|
||||
if ($method == $key) {
|
||||
return $value[$key];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getPropertyByAnnotation(string $attribute, string $class, string $method): mixed
|
||||
{
|
||||
$class = self::getAttributeTrees($attribute, $class);
|
||||
if (empty($class) || !isset($class['property'])) {
|
||||
return [];
|
||||
}
|
||||
foreach ($class['property'] as $value) {
|
||||
$key = key($value);
|
||||
if ($method == $key) {
|
||||
return $value[$key];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass|string $class
|
||||
* @return array
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public static function getMethods(ReflectionClass|string $class): array
|
||||
{
|
||||
if (is_string($class)) {
|
||||
$class = self::getReflect($class);
|
||||
}
|
||||
return static::$_classMethod[$class->getName()] ?? [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
* @return ReflectionProperty[]
|
||||
*/
|
||||
#[Pure] public static function getProperty(ReflectionClass $class): array
|
||||
{
|
||||
return static::$_classProperty[$class->getName()] ?? [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
* @return array
|
||||
*/
|
||||
#[Pure] public static function getPropertyAnnotation(ReflectionClass $class): array
|
||||
{
|
||||
return static::$_classPropertyAnnotation[$class->getName()] ?? [];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
<?php
|
||||
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Kiri;
|
||||
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Kiri;
|
||||
|
||||
/**
|
||||
* Class Environmental
|
||||
|
||||
@@ -9,150 +9,128 @@ declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Error;
|
||||
|
||||
use Closure;
|
||||
use ErrorException;
|
||||
use Exception;
|
||||
use Kiri\Message\Handler\Formatter\IFormatter;
|
||||
use Kiri\Abstracts\Component;
|
||||
use Kiri\Core\Json;
|
||||
use Kiri\Events\EventDispatch;
|
||||
use Kiri;
|
||||
use Kiri\Message\Events\OnAfterRequest;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Kiri\Di\Inject\Container;
|
||||
use ReflectionException;
|
||||
use Kiri\Events\OnSystemError;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class ErrorHandler
|
||||
*
|
||||
* hahahah
|
||||
* @package Kiri\Base
|
||||
* @property-read $asError
|
||||
*/
|
||||
class ErrorHandler extends Component implements ErrorInterface
|
||||
{
|
||||
|
||||
/** @var ?IFormatter $message */
|
||||
private ?IFormatter $message = NULL;
|
||||
|
||||
public string $category = 'app';
|
||||
|
||||
/**
|
||||
* 错误处理注册
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
// ini_set('display_errors', '1');
|
||||
set_exception_handler([$this, 'exceptionHandler']);
|
||||
if (defined('HHVM_VERSION')) {
|
||||
set_error_handler([$this, 'errorHandler']);
|
||||
} else {
|
||||
set_error_handler([$this, 'errorHandler']);
|
||||
}
|
||||
register_shutdown_function([$this, 'shutdown']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function shutdown()
|
||||
{
|
||||
$lastError = error_get_last();
|
||||
if (empty($lastError) || $lastError['type'] !== E_ERROR) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->category = 'shutdown';
|
||||
|
||||
$messages = explode(PHP_EOL, $lastError['message']);
|
||||
|
||||
$message = array_shift($messages);
|
||||
|
||||
$this->sendError($message, $lastError['file'], $lastError['line']);
|
||||
}
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public string $category = 'app';
|
||||
|
||||
|
||||
/**
|
||||
* @param \Throwable $exception
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exceptionHandler(\Throwable $exception)
|
||||
{
|
||||
$this->category = 'exception';
|
||||
|
||||
di(EventDispatch::class)->dispatch(new OnAfterRequest());
|
||||
|
||||
$this->sendError($exception->getMessage(), $exception->getFile(), $exception->getLine());
|
||||
}
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
#[Container(ContainerInterface::class)]
|
||||
public ContainerInterface $container;
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*
|
||||
* 以异常形式抛出错误,防止执行后续程序
|
||||
*/
|
||||
public function errorHandler()
|
||||
{
|
||||
$error = func_get_args();
|
||||
|
||||
$path = ['file' => $error[2], 'line' => $error[3]];
|
||||
|
||||
if ($error[0] === 0) {
|
||||
$error[0] = 500;
|
||||
}
|
||||
|
||||
$data = Json::to(500, $error[1], $path);
|
||||
|
||||
Kiri::app()->error($data, 'error');
|
||||
|
||||
di(EventDispatch::class)->dispatch(new OnAfterRequest());
|
||||
/**
|
||||
* @param array|Closure|null $callback
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function registerExceptionHandler(null|array|Closure $callback): void
|
||||
{
|
||||
if (empty($callback)) {
|
||||
$callback = [$this, 'exceptionHandler'];
|
||||
} else if (is_array($callback) && is_string($callback[0])) {
|
||||
$callback[0] = $this->container->get($callback[0]);
|
||||
}
|
||||
set_exception_handler($callback);
|
||||
}
|
||||
|
||||
|
||||
throw new \ErrorException($error[1], $error[0], 1, $error[2], $error[3]);
|
||||
}
|
||||
/**
|
||||
* @param array|Closure|null $callback
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function registerErrorHandler(null|array|Closure $callback): void
|
||||
{
|
||||
if (empty($callback)) {
|
||||
$callback = [$this, 'errorHandler'];
|
||||
} else if (is_array($callback) && is_string($callback[0])) {
|
||||
$callback[0] = $this->container->get($callback[0]);
|
||||
}
|
||||
set_error_handler($callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param $file
|
||||
* @param $line
|
||||
* @param int $code
|
||||
* @return false|string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function sendError($message, $file, $line, $code = 500): bool|string
|
||||
{
|
||||
$path = ['file' => $file, 'line' => $line];
|
||||
|
||||
var_dump(func_get_args());
|
||||
/**
|
||||
* @param array|Closure|null $callback
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function registerShutdownHandler(null|array|Closure $callback): void
|
||||
{
|
||||
if (empty($callback)) {
|
||||
$callback = [$this, 'shutdown'];
|
||||
} else if (is_array($callback) && is_string($callback[0])) {
|
||||
$callback[0] = $this->container->get($callback[0]);
|
||||
}
|
||||
register_shutdown_function($callback);
|
||||
}
|
||||
|
||||
$data = Json::to($code, $this->category . ': ' . $message, $path);
|
||||
|
||||
write($data, $this->category);
|
||||
/**
|
||||
* @return void
|
||||
* @throws
|
||||
* @throws
|
||||
*/
|
||||
public function shutdown(): void
|
||||
{
|
||||
$lastError = error_get_last();
|
||||
if (empty($lastError) || $lastError['type'] !== E_ERROR) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
$this->getLogger()->failure($lastError['message'] . PHP_EOL);
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getErrorMessage(): mixed
|
||||
{
|
||||
$message = $this->message;
|
||||
$this->message = NULL;
|
||||
return $message->getData();
|
||||
}
|
||||
event(new OnSystemError());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getAsError(): bool
|
||||
{
|
||||
return $this->message !== NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param string $category
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function writer($message, string $category = 'app')
|
||||
{
|
||||
Kiri::app()->debug($message, $category);
|
||||
}
|
||||
/**
|
||||
* @param Throwable $exception
|
||||
*
|
||||
* @throws
|
||||
*/
|
||||
public function exceptionHandler(Throwable $exception): void
|
||||
{
|
||||
$this->category = 'exception';
|
||||
|
||||
$this->getLogger()->failure($exception);
|
||||
|
||||
event(new OnSystemError());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws
|
||||
*/
|
||||
public function errorHandler()
|
||||
{
|
||||
$error = func_get_args();
|
||||
|
||||
event(new OnSystemError());
|
||||
|
||||
throw new ErrorException($error[1], $error[0], 1, $error[2], $error[3]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,4 @@ namespace Kiri\Error;
|
||||
interface ErrorInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param $file
|
||||
* @param $line
|
||||
* @param int $code
|
||||
* @return mixed
|
||||
*/
|
||||
public function sendError($message, $file, $line, $code = 500): mixed;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: admin
|
||||
* Date: 2019-03-22
|
||||
* Time: 14:36
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Error;
|
||||
|
||||
use Exception;
|
||||
use Kiri\Abstracts\Component;
|
||||
use Kiri\Core\Json;
|
||||
use Kiri;
|
||||
use Kiri\Annotation\Inject;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class Logger
|
||||
* @package Kiri\Error
|
||||
* @mixin \Kiri\Abstracts\Logger
|
||||
*/
|
||||
class Logger extends Component
|
||||
{
|
||||
|
||||
private array $logs = [];
|
||||
|
||||
|
||||
/**
|
||||
* inject logger
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
#[Inject(LoggerInterface::class)]
|
||||
public LoggerInterface $logger;
|
||||
|
||||
|
||||
private array $sources = [];
|
||||
|
||||
|
||||
/**
|
||||
* @param string $application
|
||||
* @return string
|
||||
*/
|
||||
public function getLastError(string $application = 'app'): string
|
||||
{
|
||||
return $this->logs[$application] ?? 'Unknown error.';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param $method
|
||||
* @return void
|
||||
*/
|
||||
public function fail($message, $method)
|
||||
{
|
||||
$this->logs[$method] = $message;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $messages
|
||||
* @param string $method
|
||||
* @throws Exception
|
||||
*/
|
||||
public function write(string $messages, string $method = 'app')
|
||||
{
|
||||
if (empty($messages)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$to_day = date('Y-m-d');
|
||||
|
||||
$fileName = storage('server-' . $to_day . '.log', $dirName = 'log/' . ($method ?? 'app'));
|
||||
|
||||
file_put_contents($fileName, '[' . date('Y-m-d H:i:s') . ']:' . PHP_EOL . $messages . PHP_EOL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Throwable $exception
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exception(Throwable $exception): mixed
|
||||
{
|
||||
$code = $exception->getCode() == 0 ? 500 : $exception->getCode();
|
||||
|
||||
$logger = Kiri::app()->getLogger();
|
||||
$logger->write(jTraceEx($exception), 'exception');
|
||||
|
||||
return Json::to($code, $exception->getMessage(), [
|
||||
'file' => $exception->getFile(),
|
||||
'line' => $exception->getLine()
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call(string $name, array $arguments): mixed
|
||||
{
|
||||
if (!method_exists($this, $name)) {
|
||||
return $this->logger->{$name}(...$arguments);
|
||||
} else {
|
||||
return $this->{$name}(...$arguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Error;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri\Message\Aspect\OnAspectInterface;
|
||||
use Kiri\Message\Aspect\OnJoinPointInterface;
|
||||
use Kiri\Message\Constrict\RequestInterface;
|
||||
use Kiri;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Class LoggerAspect
|
||||
* @package Kiri\Error
|
||||
*/
|
||||
class LoggerAspect implements OnAspectInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param OnJoinPointInterface $joinPoint
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function process(OnJoinPointInterface $joinPoint): mixed
|
||||
{
|
||||
$time = microtime(true);
|
||||
|
||||
$response = $joinPoint->process();
|
||||
|
||||
$this->print_runtime($time);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $startTime
|
||||
* @throws Exception
|
||||
*/
|
||||
private function print_runtime($startTime)
|
||||
{
|
||||
$request = Kiri::getDi()->get(RequestInterface::class);
|
||||
$runTime = round(microtime(true) - $startTime, 6);
|
||||
|
||||
$logger = Kiri::getDi()->get(LoggerInterface::class);
|
||||
$logger->debug(sprintf('run %s use time %6f', $request->getUri()->__toString(), $runTime));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Error;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri\Core\Json;
|
||||
use Kiri\Exception\ComponentException;
|
||||
use Kiri;
|
||||
use Kiri\Server\Abstracts\BaseProcess;
|
||||
use Kiri\Server\Broadcast\OnBroadcastInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Process;
|
||||
|
||||
/**
|
||||
* Class LoggerProcess
|
||||
* @package Kiri\Error
|
||||
*/
|
||||
class LoggerProcess extends BaseProcess
|
||||
{
|
||||
|
||||
|
||||
public string $name = 'logger process';
|
||||
|
||||
|
||||
/**
|
||||
* @param Process $process
|
||||
* @throws ComponentException
|
||||
*/
|
||||
public function process(Process $process): void
|
||||
{
|
||||
// TODO: Implement onHandler() method.
|
||||
$this->message($process);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param OnBroadcastInterface $message
|
||||
* @return void
|
||||
*/
|
||||
public function onBroadcast(OnBroadcastInterface $message): void
|
||||
{
|
||||
$logger = Kiri::getDi()->get(LoggerInterface::class);
|
||||
$logger->debug($message->data . '::' . static::class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Process $process
|
||||
* @throws ComponentException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function message(Process $process)
|
||||
{
|
||||
if ($this->isStop()) {
|
||||
return;
|
||||
}
|
||||
$message = Json::decode($process->read());
|
||||
if (!empty($message)) {
|
||||
Kiri::writeFile($this->getDirName($message), $message[0], FILE_APPEND);
|
||||
|
||||
$this->checkLogFile($message[1]);
|
||||
}
|
||||
|
||||
Coroutine\System::sleep(1);
|
||||
|
||||
$this->message($process);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getDirName($message): string
|
||||
{
|
||||
return storage('server-' . date('Y-m-d') . '.log', $message[1]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $dirName
|
||||
* @throws Exception
|
||||
*/
|
||||
private function checkLogFile($dirName)
|
||||
{
|
||||
$files = new \DirectoryIterator(storage(null, $dirName));
|
||||
if ($files->getSize() < 15) {
|
||||
return;
|
||||
}
|
||||
Coroutine\System::exec('find ' . storage(null, $dirName) . '/ -mtime +15 -name "*.log" -exec rm -rf {} \;');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Error;
|
||||
|
||||
use Kiri\Abstracts\Component;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
use Monolog\Handler\RotatingFileHandler;
|
||||
use Monolog\Logger;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use ReflectionException;
|
||||
|
||||
|
||||
/**
|
||||
* @see LoggerInterface
|
||||
* @method error(string $message, array $context = array())
|
||||
* @method log($level, $message, array $context = array())
|
||||
* @method debug($message, array $context = array())
|
||||
* @method info($message, array $context = array())
|
||||
* @method notice($message, array $context = array())
|
||||
* @method warning($message, array $context = array())
|
||||
* @method critical($message, array $context = array())
|
||||
* @method alert($message, array $context = array())
|
||||
* @method emergency($message, array $context = array())
|
||||
*/
|
||||
class StdoutLogger extends Component
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private array $errors = [];
|
||||
|
||||
|
||||
/**
|
||||
* @var Logger
|
||||
*/
|
||||
protected Logger $logger;
|
||||
|
||||
protected array $levels;
|
||||
|
||||
|
||||
/**
|
||||
* StdoutLogger construct
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->logger = new Logger(\config('id'));
|
||||
$this->levels = [
|
||||
'debug' => $this->logger::DEBUG,
|
||||
'info' => $this->logger::INFO,
|
||||
'notice' => $this->logger::NOTICE,
|
||||
'warning' => $this->logger::WARNING,
|
||||
'error' => $this->logger::ERROR,
|
||||
'critical' => $this->logger::CRITICAL,
|
||||
'alert' => $this->logger::ALERT,
|
||||
'emergency' => $this->logger::EMERGENCY,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @param string $model
|
||||
* @return bool
|
||||
*/
|
||||
public function failure($message, string $model = 'app'): bool
|
||||
{
|
||||
if ($message instanceof \Exception) {
|
||||
$this->errors[$model] = $message->getMessage();
|
||||
} else {
|
||||
$this->errors[$model] = $message;
|
||||
}
|
||||
return $this->dump($message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $message
|
||||
* @return bool
|
||||
*/
|
||||
protected function dump($message): bool
|
||||
{
|
||||
$message = throwable($message);
|
||||
if (str_contains($message, 'inotify_rm_watch')) {
|
||||
return false;
|
||||
}
|
||||
file_put_contents('php://output', '[' . date('Y-m-d H:i:s') . '] ' . $message, FILE_APPEND);
|
||||
$this->error($message, []);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
public function println(string $message): void
|
||||
{
|
||||
file_put_contents('php://output', '[' . date('Y-m-d H:i:s') . '] ' . $message . PHP_EOL, FILE_APPEND);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function __call(string $name, array $arguments)
|
||||
{
|
||||
try {
|
||||
if (method_exists($this->logger, $name)) {
|
||||
$this->createHandler($name)->$name(...$arguments);
|
||||
} else if (method_exists($this, $name)) {
|
||||
$this->{$name}(...$arguments);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
file_put_contents('php://output', '[' . date('Y-m-d H:i:s') . '] ' . $exception->getMessage(), FILE_APPEND);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return Logger
|
||||
*/
|
||||
protected function createHandler(string $name): Logger
|
||||
{
|
||||
if (!$this->logger->isHandling($this->levels[$name])) {
|
||||
$handler = new RotatingFileHandler(APP_PATH . 'storage/logs/' . $name . '/kiri.log', $this->levels[$name]);
|
||||
$handler->setFormatter(new LineFormatter("[%datetime%] %channel%.%level_name%: %message% %context%\n", 'Y-m-d H:i:s'));
|
||||
$this->logger->pushHandler($handler);
|
||||
}
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $model
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLastError(string $model = 'app'): mixed
|
||||
{
|
||||
return $this->errors[$model] ?? 'Unknown error.';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,238 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Kiri;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri\Abstracts\Component;
|
||||
use Kiri;
|
||||
/**
|
||||
* Class Event
|
||||
* @package Kiri
|
||||
*/
|
||||
class Event extends Component
|
||||
{
|
||||
|
||||
public bool $isVide = true;
|
||||
|
||||
private static array $_events = [];
|
||||
|
||||
|
||||
const PIPE_MESSAGE = 'SERVER:PIPE:MESSAGE';
|
||||
const TASK_FINISH = 'SERVER:TASK::FINISH';
|
||||
|
||||
const EVENT_AFTER_REQUEST = 'SERVER:REQUEST:AFTER:START';
|
||||
const EVENT_BEFORE_REQUEST = 'SERVER:REQUEST:BEFORE:START';
|
||||
const RECEIVE_CONNECTION = 'SERVER:RECEIVE:CONNECTION';
|
||||
|
||||
|
||||
const SYSTEM_RESOURCE_RELEASES = 'SYSTEM::RESOURCE::RELEASES';
|
||||
const SYSTEM_RESOURCE_CLEAN = 'SYSTEM::RESOURCE::CLEAN';
|
||||
|
||||
|
||||
const PROCESS_WORKER_STOP = 'SERVER:PROCESS:WORKER:STOP';
|
||||
|
||||
const SERVER_AFTER_RELOAD = 'SERVER:AFTER:RELOAD';
|
||||
const SERVER_BEFORE_RELOAD = 'SERVER:BEFORE:RELOAD';
|
||||
const SERVER_CONNECT = 'SERVER:CONNECT';
|
||||
const SERVER_PACKAGE = 'SERVER:PACKAGE';
|
||||
const SERVER_RECEIVE = 'SERVER:RECEIVE';
|
||||
|
||||
const SERVER_EVENT_START = 'SERVER:EVENT:START';
|
||||
const SERVER_MANAGER_START = 'SERVER:EVENT:MANAGER:START';
|
||||
const SERVER_MANAGER_STOP = 'SERVER:EVENT:MANAGER:START';
|
||||
const SERVER_WORKER_STOP = 'SERVER:EVENT:WORKER:STOP';
|
||||
const SERVER_WORKER_START = 'SERVER:EVENT:WORKER:START';
|
||||
const SERVER_AFTER_WORKER_START = 'SERVER:EVENT:AFTER:WORKER:START';
|
||||
const SERVER_BEFORE_START = 'SERVER:EVENT:BEFORE:START';
|
||||
const BEFORE_COMMAND_EXECUTE = 'COMMAND:EVENT:BEFORE:EXECUTE';
|
||||
const AFTER_COMMAND_EXECUTE = 'COMMAND:EVENT:AFTER:EXECUTE';
|
||||
const SERVER_TASK_START = 'SERVER:EVENT:TASK:START';
|
||||
const SERVER_WORKER_EXIT = 'SERVER:EVENT:WORKER:EXIT';
|
||||
const SERVER_WORKER_ERROR = 'SERVER:EVENT:WORKER:ERROR';
|
||||
const SERVER_SHUTDOWN = 'SERVER:EVENT:SHUTDOWN';
|
||||
|
||||
const SERVER_HANDSHAKE = 'on handshake';
|
||||
const SERVER_MESSAGE = 'on message';
|
||||
const SERVER_CLIENT_CLOSE = 'SERVER:CLIENT:CLOSE';
|
||||
|
||||
const SERVER_ON_START = 'Start';
|
||||
const SERVER_ON_SHUTDOWN = 'Shutdown';
|
||||
const SERVER_ON_WORKER_START = 'WorkerStart';
|
||||
const SERVER_ON_WORKER_STOP = 'WorkerStop';
|
||||
const SERVER_ON_WORKER_EXIT = 'WorkerExit';
|
||||
const SERVER_ON_CONNECT = 'Connect';
|
||||
const SERVER_ON_RECEIVE = 'Receive';
|
||||
const SERVER_ON_PACKET = 'Packet';
|
||||
const SERVER_ON_REQUEST = 'request';
|
||||
const SERVER_ON_CLOSE = 'Close';
|
||||
const SERVER_ON_TASK = 'Task';
|
||||
const SERVER_ON_FINISH = 'Finish';
|
||||
const SERVER_ON_PIPE_MESSAGE = 'OnPipeMessageInterface';
|
||||
const SERVER_ON_WORKER_ERROR = 'WorkerError';
|
||||
const SERVER_ON_MANAGER_START = 'ManagerStart';
|
||||
const SERVER_ON_MANAGER_STOP = 'ManagerStop';
|
||||
const SERVER_ON_BEFORE_RELOAD = 'BeforeReload';
|
||||
const SERVER_ON_AFTER_RELOAD = 'AfterReload';
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $callback
|
||||
* @param bool $isAppend
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function on($name, $callback, bool $isAppend = false)
|
||||
{
|
||||
if (!isset(static::$_events[$name])) {
|
||||
static::$_events[$name] = [];
|
||||
}
|
||||
if (is_array($callback) && is_string($callback[0])) {
|
||||
if (!class_exists($callback[0])) {
|
||||
throw new Exception('Undefined callback class.');
|
||||
}
|
||||
$callback[0] = di($callback[0]);
|
||||
}
|
||||
if (static::exists($name, $callback)) {
|
||||
return;
|
||||
}
|
||||
if (!empty(static::$_events[$name]) && $isAppend === true) {
|
||||
array_unshift(static::$_events[$name], [$callback]);
|
||||
} else {
|
||||
static::$_events[$name][] = [$callback];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $callback
|
||||
*/
|
||||
public static function of($name, $callback): void
|
||||
{
|
||||
if (!isset(static::$_events[$name])) {
|
||||
return;
|
||||
}
|
||||
foreach (static::$_events[$name] as $index => $event) {
|
||||
[$handler] = $event;
|
||||
if ($handler !== $callback) {
|
||||
continue;
|
||||
}
|
||||
unset(static::$_events[$name][$index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
*/
|
||||
public static function offName($name): void
|
||||
{
|
||||
unset(static::$_events[$name]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $callback
|
||||
* @return bool
|
||||
*/
|
||||
public static function exists($name, $callback): bool
|
||||
{
|
||||
if ($callback instanceof \Closure || !isset(static::$_events[$name])) {
|
||||
return false;
|
||||
}
|
||||
foreach (static::$_events[$name] as $event) {
|
||||
[$handler] = $event;
|
||||
if ($handler === $callback) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $handler
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($name, $handler): mixed
|
||||
{
|
||||
if (!static::exists($name, $handler)) {
|
||||
return null;
|
||||
}
|
||||
if (empty($handler)) {
|
||||
return static::$_events[$name];
|
||||
}
|
||||
foreach (static::$_events[$name] as $event) {
|
||||
[$callback] = $event;
|
||||
if ($callback === $handler) {
|
||||
return [$event];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static function clean()
|
||||
{
|
||||
static::$_events = [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param array $params
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function dispatch($name, array $params = []): bool
|
||||
{
|
||||
return static::trigger($name, $params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $parameter
|
||||
* @param false $is_remove
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function trigger($name, $parameter = null, bool $is_remove = false): bool
|
||||
{
|
||||
foreach ((static::$_events[$name] ?? []) as $key => $event) {
|
||||
static::execute($event, $parameter);
|
||||
if ($event instanceof \Closure) {
|
||||
unset(static::$_events[$name][$key]);
|
||||
}
|
||||
}
|
||||
if ($is_remove) {
|
||||
unset(static::$_events[$name]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $event
|
||||
* @param $parameter
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function execute($event, $parameter): void
|
||||
{
|
||||
try {
|
||||
call_user_func($event[0], ...$parameter);
|
||||
} catch (\Throwable $throwable) {
|
||||
logger()->addError($throwable, 'throwable');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -2,14 +2,16 @@
|
||||
|
||||
namespace Kiri\Events;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
||||
class OnAfterCommandExecute
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
/**
|
||||
* @param Command $command
|
||||
*/
|
||||
public function __construct(public Command $command)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,17 @@
|
||||
|
||||
namespace Kiri\Events;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
||||
class OnBeforeCommandExecute
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param Command $command
|
||||
*/
|
||||
public function __construct(public Command $command)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Events;
|
||||
|
||||
class OnSystemError
|
||||
{
|
||||
|
||||
}
|
||||
@@ -21,7 +21,7 @@ class AuthException extends \Exception
|
||||
* @param int $code
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct($message = "", $code = 0, Throwable $previous = null)
|
||||
public function __construct(string $message = "", int $code = 0, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, 4001, $previous);
|
||||
}
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\FileListen;
|
||||
|
||||
use Exception;
|
||||
use Kiri;
|
||||
use Kiri\Abstracts\Config;
|
||||
use Kiri\Annotation\Inject;
|
||||
use Kiri\Core\Json;
|
||||
use Kiri\Error\Logger;
|
||||
use Kiri\Exception\ConfigException;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Process;
|
||||
use Swoole\Timer;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class HotReload extends Command
|
||||
{
|
||||
|
||||
|
||||
public bool $isReloading = FALSE;
|
||||
public bool $isReloadingOut = FALSE;
|
||||
public ?array $dirs = [];
|
||||
|
||||
public int $events;
|
||||
|
||||
public int $int = -1;
|
||||
|
||||
|
||||
private ?Process $process = NULL;
|
||||
|
||||
|
||||
public Inotify|Scaner $driver;
|
||||
|
||||
|
||||
#[Inject(Logger::class)]
|
||||
public Logger $logger;
|
||||
|
||||
|
||||
protected mixed $source = NULL;
|
||||
|
||||
protected mixed $pipes = [];
|
||||
|
||||
protected ?Coroutine\Channel $channel = NULL;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('sw:wather')->setDescription('server start');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function initCore()
|
||||
{
|
||||
set_error_handler([$this, 'errorHandler']);
|
||||
$this->dirs = Config::get('inotify', [APP_PATH . 'app']);
|
||||
if (!extension_loaded('inotify')) {
|
||||
$this->driver = Kiri::getDi()->make(Scaner::class, [$this->dirs, $this]);
|
||||
} else {
|
||||
$this->driver = Kiri::getDi()->make(Inotify::class, [$this->dirs, $this]);
|
||||
}
|
||||
$this->clearOtherService();
|
||||
$this->setProcessName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function setProcessName()
|
||||
{
|
||||
swoole_async_set(['enable_coroutine' => FALSE]);
|
||||
if (Kiri::getPlatform()->isLinux()) {
|
||||
swoole_set_process_name('[' . Config::get('id', 'sw service.') . '].sw:wather');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function clearOtherService()
|
||||
{
|
||||
if (file_exists(storage('.manager.pid'))) {
|
||||
$pid = (int)file_get_contents(storage('.manager.pid'));
|
||||
if ($pid > 0 && Process::kill($pid, 0)) {
|
||||
Process::kill($pid, 15) && Process::wait(TRUE);
|
||||
}
|
||||
}
|
||||
file_put_contents(storage('.manager.pid'), getmypid());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function errorHandler()
|
||||
{
|
||||
$error = func_get_args();
|
||||
|
||||
$path = ['file' => $error[2], 'line' => $error[3]];
|
||||
|
||||
if ($error[0] === 0) {
|
||||
$error[0] = 500;
|
||||
}
|
||||
$data = Json::to(500, $error[1], $path);
|
||||
|
||||
$this->logger->error($data, 'error');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->initCore();
|
||||
|
||||
$this->trigger_reload();
|
||||
Timer::tick(1000, fn() => $this->healthCheck());
|
||||
|
||||
Process::signal(SIGTERM, [$this, 'onSignal']);
|
||||
Process::signal(SIGKILL, [$this, 'onSignal']);
|
||||
|
||||
$this->driver->start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function healthCheck()
|
||||
{
|
||||
$pid = (int)file_get_contents(storage('.swoole.pid'));
|
||||
if ($this->int == 1) {
|
||||
return;
|
||||
}
|
||||
if (empty($pid)) {
|
||||
$this->logger->warning('service is shutdown you need reload.');
|
||||
$this->trigger_reload();
|
||||
} else if (!Process::kill($pid, 0)) {
|
||||
$this->logger->warning('service is shutdown you need reload.');
|
||||
$this->trigger_reload();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @throws Exception
|
||||
*/
|
||||
public function onSignal($data)
|
||||
{
|
||||
if (!$data) {
|
||||
return;
|
||||
}
|
||||
Timer::clearAll();
|
||||
$this->driver->clear();
|
||||
$this->stopServer();
|
||||
while ($ret = Process::wait(TRUE)) {
|
||||
echo "PID={$ret['pid']}\n";
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function stopServer()
|
||||
{
|
||||
$pid = file_get_contents(storage('.swoole.pid'));
|
||||
if (!empty($pid) && Process::kill($pid, 0)) {
|
||||
Process::kill($pid, SIGTERM);
|
||||
}
|
||||
if ($this->process && Process::kill($this->process->pid, 0)) {
|
||||
Process::kill($this->process->pid) && Process::wait(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 重启
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function trigger_reload(string $path = '')
|
||||
{
|
||||
$this->logger->warning('change reload');
|
||||
var_dump($path);
|
||||
if (!empty($path) && str_starts_with($path, CONTROLLER_PATH)) {
|
||||
$pid = file_get_contents(storage('.swoole.pid'));
|
||||
if (!empty($pid) && Process::kill($pid, 0)) {
|
||||
Process::kill($pid, SIGUSR1);
|
||||
}
|
||||
} else {
|
||||
$this->int = 1;
|
||||
$this->stopServer();
|
||||
$this->process = new Process(function (Process $process) {
|
||||
$process->exec(PHP_BINARY, [APP_PATH . "kiri.php", "sw:server", "start"]);
|
||||
});
|
||||
$this->process->start();
|
||||
$this->int = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\FileListen;
|
||||
|
||||
use Exception;
|
||||
use Swoole\Event;
|
||||
use Swoole\Timer;
|
||||
|
||||
class Inotify
|
||||
{
|
||||
|
||||
private mixed $inotify;
|
||||
private mixed $events;
|
||||
|
||||
private array $watchFiles = [];
|
||||
|
||||
|
||||
public bool $isReloading = FALSE;
|
||||
|
||||
|
||||
protected int $cid;
|
||||
|
||||
const IG_DIR = [APP_PATH . 'commands', APP_PATH . '.git', APP_PATH . '.gitee'];
|
||||
|
||||
|
||||
/**
|
||||
* @param array $dirs
|
||||
* @param HotReload $process
|
||||
*/
|
||||
public function __construct(protected array $dirs, public HotReload $process)
|
||||
{
|
||||
set_error_handler([$this, 'error']);
|
||||
set_exception_handler([$this, 'error']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function error(): void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function start()
|
||||
{
|
||||
$this->inotify = inotify_init();
|
||||
$this->events = IN_MODIFY | IN_DELETE | IN_CREATE | IN_MOVE;
|
||||
foreach ($this->dirs as $dir) {
|
||||
if (!is_dir($dir)) continue;
|
||||
$this->watch($dir);
|
||||
}
|
||||
$this->process->int = -1;
|
||||
Event::add($this->inotify, [$this, 'check']);
|
||||
Event::wait();
|
||||
}
|
||||
|
||||
|
||||
public function clear()
|
||||
{
|
||||
Event::del($this->inotify);
|
||||
Event::exit();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 开始监听
|
||||
* @throws Exception
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
if (!($events = inotify_read($this->inotify))) {
|
||||
return;
|
||||
}
|
||||
if ($this->isReloading) {
|
||||
return;
|
||||
}
|
||||
|
||||
$LISTEN_TYPE = [IN_CREATE, IN_DELETE, IN_MODIFY, IN_MOVED_TO, IN_MOVED_FROM];
|
||||
foreach ($events as $ev) {
|
||||
if (!in_array($ev['mask'], $LISTEN_TYPE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
var_dump($ev);
|
||||
|
||||
//非重启类型
|
||||
if (str_ends_with($ev['name'], '.php')) {
|
||||
|
||||
Timer::after(3000, fn() => $this->reload($ev['name']));
|
||||
$this->isReloading = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function reload($path)
|
||||
{
|
||||
$this->process->trigger_reload($path);
|
||||
$this->process->int = -1;
|
||||
|
||||
$this->clearWatch();
|
||||
foreach ($this->dirs as $root) {
|
||||
$this->watch($root);
|
||||
}
|
||||
$this->isReloading = FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function clearWatch()
|
||||
{
|
||||
foreach ($this->watchFiles as $wd) {
|
||||
@inotify_rm_watch($this->inotify, $wd);
|
||||
}
|
||||
$this->watchFiles = [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $dir
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function watch($dir): bool
|
||||
{
|
||||
//目录不存在
|
||||
if (!is_dir($dir)) {
|
||||
return logger()->addError("[$dir] is not a directory.");
|
||||
}
|
||||
//避免重复监听
|
||||
if (isset($this->watchFiles[$dir])) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (in_array($dir, self::IG_DIR)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$wd = @inotify_add_watch($this->inotify, $dir, $this->events);
|
||||
$this->watchFiles[$dir] = $wd;
|
||||
|
||||
$files = scandir($dir);
|
||||
foreach ($files as $f) {
|
||||
if ($f == '.' || $f == '..') {
|
||||
continue;
|
||||
}
|
||||
$path = $dir . '/' . $f;
|
||||
//递归目录
|
||||
if (is_dir($path)) {
|
||||
$this->watch($path);
|
||||
} else if (!str_ends_with($f, '.php')) {
|
||||
continue;
|
||||
}
|
||||
//检测文件类型
|
||||
if (strstr($f, '.') == '.php') {
|
||||
$wd = @inotify_add_watch($this->inotify, $path, $this->events);
|
||||
$this->watchFiles[$path] = $wd;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\FileListen;
|
||||
|
||||
use Exception;
|
||||
|
||||
class Scaner
|
||||
{
|
||||
|
||||
private array $md5Map = [];
|
||||
|
||||
public bool $isReloading = FALSE;
|
||||
|
||||
|
||||
/**
|
||||
* @param array $dirs
|
||||
* @param HotReload $process
|
||||
*/
|
||||
public function __construct(protected array $dirs, public HotReload $process)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function start(): void
|
||||
{
|
||||
$this->loadDirs();
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bool $isReload
|
||||
* @throws Exception
|
||||
*/
|
||||
private function loadDirs(bool $isReload = FALSE)
|
||||
{
|
||||
foreach ($this->dirs as $value) {
|
||||
if (is_bool($path = realpath($value))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_dir($path)) continue;
|
||||
|
||||
$this->loadByDir($path, $isReload);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @param bool $isReload
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
private function loadByDir($path, bool $isReload = FALSE): void
|
||||
{
|
||||
if (!is_string($path)) {
|
||||
return;
|
||||
}
|
||||
$path = rtrim($path, '/');
|
||||
foreach (glob(realpath($path) . '/*') as $value) {
|
||||
if (is_dir($value)) {
|
||||
$this->loadByDir($value, $isReload);
|
||||
}
|
||||
if (is_file($value)) {
|
||||
if ($this->checkFile($value, $isReload)) {
|
||||
$this->isReloading = TRUE;
|
||||
|
||||
sleep(2);
|
||||
|
||||
$this->timerReload($value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @param $isReload
|
||||
* @return bool
|
||||
*/
|
||||
private function checkFile($value, $isReload): bool
|
||||
{
|
||||
$md5 = md5($value);
|
||||
$mTime = filectime($value);
|
||||
if (!isset($this->md5Map[$md5])) {
|
||||
if ($isReload) {
|
||||
return TRUE;
|
||||
}
|
||||
$this->md5Map[$md5] = $mTime;
|
||||
} else {
|
||||
if ($this->md5Map[$md5] != $mTime) {
|
||||
if ($isReload) {
|
||||
return TRUE;
|
||||
}
|
||||
$this->md5Map[$md5] = $mTime;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function timerReload($path)
|
||||
{
|
||||
$this->isReloading = TRUE;
|
||||
|
||||
$this->process->trigger_reload($path);
|
||||
|
||||
$this->loadDirs();
|
||||
|
||||
$this->process->int = -1;
|
||||
|
||||
$this->isReloading = FALSE;
|
||||
$this->process->isReloadingOut = FALSE;
|
||||
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
|
||||
private bool $isStop = FALSE;
|
||||
|
||||
public function clear()
|
||||
{
|
||||
$this->isStop = TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function tick()
|
||||
{
|
||||
if ($this->isReloading || $this->isStop) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->loadDirs(TRUE);
|
||||
|
||||
sleep(2);
|
||||
|
||||
$this->tick();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri;
|
||||
|
||||
|
||||
interface IAspect
|
||||
{
|
||||
|
||||
|
||||
public function before(): void;
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $response
|
||||
*/
|
||||
public function after(mixed $response): void;
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $handler
|
||||
* @param array $params
|
||||
* @return mixed
|
||||
*/
|
||||
public function invoke(mixed $handler, array $params = []): mixed;
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri;
|
||||
|
||||
|
||||
interface IProxy
|
||||
{
|
||||
|
||||
public function execute();
|
||||
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Pool;
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
|
||||
trait Alias
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $cds
|
||||
* @param false $isMaster
|
||||
* @return string
|
||||
*/
|
||||
#[Pure] public function name($cds, bool $isMaster = false): string
|
||||
{
|
||||
if ($isMaster === true) {
|
||||
return $cds . '_master';
|
||||
} else {
|
||||
return $cds . '_slave';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Pool;
|
||||
|
||||
use Closure;
|
||||
use Database\Mysql\PDO;
|
||||
use Exception;
|
||||
use Kiri\Abstracts\Component;
|
||||
use Kiri\Abstracts\Config;
|
||||
use Kiri\Context;
|
||||
use Kiri;
|
||||
use Swoole\Error;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class Connection
|
||||
* @package Kiri\Pool
|
||||
*/
|
||||
class Connection extends Component
|
||||
{
|
||||
|
||||
use Alias;
|
||||
|
||||
|
||||
/**
|
||||
* @param $cds
|
||||
* @return bool
|
||||
*
|
||||
* db is in transaction
|
||||
* @throws Exception
|
||||
*/
|
||||
public function inTransaction($cds): bool
|
||||
{
|
||||
$name = $this->name('Mysql:' . $cds, true);
|
||||
$connection = Context::getContext($name);
|
||||
if ($connection instanceof PDO) {
|
||||
return $connection->inTransaction();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $coroutineName
|
||||
* @throws Exception
|
||||
*/
|
||||
public function beginTransaction($coroutineName)
|
||||
{
|
||||
$coroutineName = $this->name('Mysql:' . $coroutineName, true);
|
||||
$connection = Context::getContext($coroutineName);
|
||||
if ($connection instanceof PDO) {
|
||||
$connection->beginTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $coroutineName
|
||||
* @throws Exception
|
||||
*/
|
||||
public function commit($coroutineName)
|
||||
{
|
||||
$coroutineName = $this->name('Mysql:' . $coroutineName, true);
|
||||
$connection = Context::getContext($coroutineName);
|
||||
if ($connection instanceof PDO) {
|
||||
$connection->commit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $coroutineName
|
||||
* @throws Exception
|
||||
*/
|
||||
public function rollback($coroutineName)
|
||||
{
|
||||
$coroutineName = $this->name('Mysql:' . $coroutineName, true);
|
||||
$connection = Context::getContext($coroutineName);
|
||||
if ($connection instanceof PDO) {
|
||||
$connection->rollBack();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $config
|
||||
* @param bool $isMaster
|
||||
* @return PDO|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get(mixed $config, bool $isMaster = false): ?PDO
|
||||
{
|
||||
$coroutineName = $this->name('Mysql:' . $config['cds'], $isMaster);
|
||||
if (($pdo = Context::getContext($coroutineName)) instanceof PDO) {
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
$minx = Config::get('databases.pool.min', 1);
|
||||
|
||||
/** @var PDO $connections */
|
||||
$connections = $this->getPool()->get($coroutineName, $this->create($coroutineName, $config), $minx);
|
||||
if (Context::hasContext('begin_' . $coroutineName)) {
|
||||
$connections->beginTransaction();
|
||||
}
|
||||
return Context::setContext($coroutineName, $connections);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $coroutineName
|
||||
* @param $config
|
||||
* @return Closure
|
||||
*/
|
||||
public function create($coroutineName, $config): Closure
|
||||
{
|
||||
return static function () use ($coroutineName, $config) {
|
||||
return Kiri::getDi()->create(PDO::class, [$config]);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $isMaster
|
||||
* @param $max
|
||||
* @throws Exception
|
||||
*/
|
||||
public function initConnections($name, $isMaster, $max)
|
||||
{
|
||||
$this->getPool()->initConnections($name, $isMaster, $max);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $coroutineName
|
||||
* @param $isMaster
|
||||
* @throws Exception
|
||||
*/
|
||||
public function release($coroutineName, $isMaster)
|
||||
{
|
||||
$coroutineName = $this->name('Mysql:' . $coroutineName, $isMaster);
|
||||
/** @var PDO $client */
|
||||
if (!($client = Context::getContext($coroutineName)) instanceof PDO) {
|
||||
return;
|
||||
}
|
||||
if ($client->inTransaction()) {
|
||||
return;
|
||||
}
|
||||
$this->getPool()->push($coroutineName, $client);
|
||||
Context::remove($coroutineName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $coroutineName
|
||||
* @return bool
|
||||
*/
|
||||
private function hasClient($coroutineName): bool
|
||||
{
|
||||
return Context::hasContext($coroutineName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* batch release
|
||||
* @throws Exception
|
||||
*/
|
||||
public function connection_clear($name, $isMaster)
|
||||
{
|
||||
$this->getPool()->clean($this->name($name, $isMaster));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $client
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkCanUse(string $name, mixed $client): bool
|
||||
{
|
||||
try {
|
||||
if (empty($client) || !($client instanceof PDO)) {
|
||||
$result = false;
|
||||
} else {
|
||||
$result = true;
|
||||
}
|
||||
} catch (Error | Throwable $exception) {
|
||||
$result = $this->addError($exception, 'mysql');
|
||||
} finally {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $coroutineName
|
||||
* @param bool $isMaster
|
||||
* @throws Exception
|
||||
*/
|
||||
public function disconnect($coroutineName, bool $isMaster = false)
|
||||
{
|
||||
Context::remove($coroutineName);
|
||||
$coroutineName = $this->name('Mysql:' . $coroutineName, $isMaster);
|
||||
$this->getPool()->clean($coroutineName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Pool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getPool(): Pool
|
||||
{
|
||||
return Kiri::getDi()->get(Pool::class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Pool\Helper;
|
||||
|
||||
interface QueueInterface
|
||||
{
|
||||
|
||||
|
||||
public function isEmpty(): bool;
|
||||
|
||||
public function push(mixed $data, float $timeout = -1): bool;
|
||||
|
||||
|
||||
public function pop(float $timeout = -1): mixed;
|
||||
|
||||
|
||||
public function stats(): array;
|
||||
|
||||
|
||||
public function close(): bool;
|
||||
|
||||
|
||||
public function length(): int;
|
||||
|
||||
|
||||
public function isFull(): bool;
|
||||
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Pool\Helper;
|
||||
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class SplQueue implements QueueInterface
|
||||
{
|
||||
|
||||
private \SplQueue $channel;
|
||||
|
||||
|
||||
public int $errCode = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @param int $max
|
||||
*/
|
||||
#[Pure] public function __construct(public int $max)
|
||||
{
|
||||
$this->channel = new \SplQueue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
// TODO: Implement isEmpty() method.
|
||||
return $this->channel->count() < 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
* @param float $timeout
|
||||
* @return bool
|
||||
*/
|
||||
public function push(mixed $data, float $timeout = -1): bool
|
||||
{
|
||||
// TODO: Implement push() method.
|
||||
$this->channel->enqueue($data);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param float $timeout
|
||||
* @return mixed
|
||||
*/
|
||||
public function pop(float $timeout = -1): mixed
|
||||
{
|
||||
// TODO: Implement pop() method.
|
||||
return $this->channel->dequeue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function stats(): array
|
||||
{
|
||||
// TODO: Implement stats() method.
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function close(): bool
|
||||
{
|
||||
// TODO: Implement close() method.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function length(): int
|
||||
{
|
||||
// TODO: Implement length() method.
|
||||
return $this->channel->count();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isFull(): bool
|
||||
{
|
||||
// TODO: Implement isFull() method.
|
||||
return $this->channel->count() >= $this->max;
|
||||
}
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri\Pool;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri\Context;
|
||||
use Kiri\Abstracts\Component;
|
||||
use Kiri\Abstracts\Config;
|
||||
use Kiri\Exception\ConfigException;
|
||||
use Kiri\Pool\Helper\SplQueue;
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Coroutine\Channel;
|
||||
|
||||
|
||||
/**
|
||||
* Class Pool
|
||||
* @package Kiri\Pool
|
||||
*/
|
||||
class Pool extends Component
|
||||
{
|
||||
|
||||
/** @var Channel[] */
|
||||
private static array $_connections = [];
|
||||
|
||||
public int $max = 60;
|
||||
|
||||
use Alias;
|
||||
|
||||
|
||||
/**
|
||||
* @param $channel
|
||||
* @param $retain_number
|
||||
* @throws Exception
|
||||
*/
|
||||
public function flush($channel, $retain_number)
|
||||
{
|
||||
$this->pop($channel, $retain_number);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Channel $channel
|
||||
* @param $retain_number
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function pop(Channel $channel, $retain_number): void
|
||||
{
|
||||
while ($channel->length() > $retain_number) {
|
||||
if (Context::inCoroutine()) {
|
||||
$connection = $channel->pop();
|
||||
if ($connection instanceof StopHeartbeatCheck) {
|
||||
$connection->stopHeartbeatCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param false $isMaster
|
||||
* @param int $max
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function initConnections($name, bool $isMaster = false, int $max = 60)
|
||||
{
|
||||
$name = $this->name($name, $isMaster);
|
||||
if (isset(static::$_connections[$name])) {
|
||||
$value = static::$_connections[$name];
|
||||
if ($value instanceof Channel || $value instanceof SplQueue) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->newChannel($name, $max);
|
||||
$this->max = $max;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return Channel|SplQueue
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getChannel($name): Channel|SplQueue
|
||||
{
|
||||
if (!isset(static::$_connections[$name])) {
|
||||
$this->newChannel($name);
|
||||
}
|
||||
if (static::$_connections[$name]->errCode == SWOOLE_CHANNEL_CLOSED) {
|
||||
throw new Exception('Channel is Close.');
|
||||
}
|
||||
return static::$_connections[$name];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
*/
|
||||
private function newChannel($name, $max = null)
|
||||
{
|
||||
if ($max == null) {
|
||||
$max = Config::get('databases.pool.max', 10);
|
||||
}
|
||||
if (Coroutine::getCid() === -1) {
|
||||
static::$_connections[$name] = new SplQueue($max);
|
||||
} else {
|
||||
static::$_connections[$name] = new Channel($max);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $callback
|
||||
* @param $minx
|
||||
* @return array
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get($name, $callback, $minx): mixed
|
||||
{
|
||||
$channel = $this->getChannel($name);
|
||||
if (!$channel->isEmpty()) {
|
||||
return $this->maxIdleQuantity($channel, $minx);
|
||||
}
|
||||
return $callback();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $channel
|
||||
* @param $minx
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function maxIdleQuantity($channel, $minx): mixed
|
||||
{
|
||||
$connection = $channel->pop();
|
||||
if ($channel->length() > $minx) {
|
||||
$this->pop($channel, $minx);
|
||||
}
|
||||
return $connection;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return bool
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function isNull($name): bool
|
||||
{
|
||||
return $this->getChannel($name)->isEmpty();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $client
|
||||
* @return bool
|
||||
* 检查连接可靠性
|
||||
*/
|
||||
public function checkCanUse(string $name, mixed $client): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasItem(string $name): bool
|
||||
{
|
||||
if (isset(static::$_connections[$name])) {
|
||||
return !static::$_connections[$name]->isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function size(string $name): mixed
|
||||
{
|
||||
if (!isset(static::$_connections[$name])) {
|
||||
return 0;
|
||||
}
|
||||
return static::$_connections[$name]->length();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $client
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function push(string $name, mixed $client)
|
||||
{
|
||||
$channel = $this->getChannel($name);
|
||||
if (!$channel->isFull()) {
|
||||
$channel->push($client);
|
||||
}
|
||||
unset($client);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @throws Exception
|
||||
*/
|
||||
public function clean(string $name)
|
||||
{
|
||||
if (!isset(static::$_connections[$name])) {
|
||||
return;
|
||||
}
|
||||
while (static::$_connections[$name]->length() > 0) {
|
||||
if (static::$_connections[$name] instanceof Channel)
|
||||
{
|
||||
if (!Context::inCoroutine())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
$client = static::$_connections[$name]->pop();
|
||||
if ($client instanceof StopHeartbeatCheck) {
|
||||
$client->stopHeartbeatCheck();
|
||||
}
|
||||
}
|
||||
static::$_connections[$name] = null;
|
||||
unset(static::$_connections[$name]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Channel[]
|
||||
*/
|
||||
protected function getChannels(): array
|
||||
{
|
||||
return static::$_connections;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Kiri\Pool;
|
||||
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Kiri\Abstracts\Component;
|
||||
use Kiri\Context;
|
||||
use Kiri\Exception\ConfigException;
|
||||
use Kiri;
|
||||
|
||||
/**
|
||||
* Class RedisClient
|
||||
* @package Kiri\Pool
|
||||
*/
|
||||
class Redis extends Component
|
||||
{
|
||||
|
||||
use Alias;
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $config
|
||||
* @param bool $isMaster
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get(mixed $config, bool $isMaster = false): mixed
|
||||
{
|
||||
$coroutineName = $this->name('Redis:' . $config['host'], $isMaster);
|
||||
if (Context::hasContext($coroutineName)) {
|
||||
return Context::getContext($coroutineName);
|
||||
}
|
||||
|
||||
$pool = $config['pool'] ?? ['min' => 1, 'max' => 100];
|
||||
|
||||
$clients = $this->getPool()->get($coroutineName, $this->create($coroutineName, $config), $pool['min'] ?? 1);
|
||||
return Context::setContext($coroutineName, $clients);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $config
|
||||
* @return Closure
|
||||
*/
|
||||
public function create(string $name, mixed $config): Closure
|
||||
{
|
||||
return static function () use ($name, $config) {
|
||||
return Kiri::getDi()->create(\Kiri\Cache\Base\Redis::class, [$config]);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @param bool $isMaster
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function release(array $config, bool $isMaster = false)
|
||||
{
|
||||
$coroutineName = $this->name('Redis:' . $config['host'], $isMaster);
|
||||
if (!Context::hasContext($coroutineName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->getPool()->push($coroutineName, Context::getContext($coroutineName));
|
||||
Context::remove($coroutineName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @param bool $isMaster
|
||||
* @throws Exception
|
||||
*/
|
||||
public function destroy(array $config, bool $isMaster = false)
|
||||
{
|
||||
$coroutineName = $this->name('Redis:' . $config['host'], $isMaster);
|
||||
$this->getPool()->clean($coroutineName);
|
||||
Context::remove($coroutineName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @param bool $isMaster
|
||||
* @throws Exception
|
||||
*/
|
||||
public function connection_clear(array $config, bool $isMaster = false)
|
||||
{
|
||||
$coroutineName = $this->name('Redis:' . $config['host'], $isMaster);
|
||||
$this->getPool()->clean($coroutineName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Pool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getPool(): Pool
|
||||
{
|
||||
return Kiri::getDi()->get(Pool::class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $isMaster
|
||||
* @param $max
|
||||
* @throws Exception
|
||||
*/
|
||||
public function initConnections($name, $isMaster, $max)
|
||||
{
|
||||
$this->getPool()->initConnections($name, $isMaster, $max);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Pool;
|
||||
|
||||
interface StopHeartbeatCheck
|
||||
{
|
||||
|
||||
|
||||
public function stopHeartbeatCheck();
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri;
|
||||
|
||||
|
||||
class Proxy
|
||||
{
|
||||
|
||||
/**
|
||||
* Proxy constructor.
|
||||
* @param IProxy $IProxy
|
||||
*/
|
||||
public function __construct(public IProxy $IProxy)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function execute(): mixed
|
||||
{
|
||||
return $this->IProxy->execute();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: whwyy
|
||||
* Date: 2018/4/27 0027
|
||||
* Time: 11:00
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kiri\Redis;
|
||||
|
||||
use Exception;
|
||||
use Kiri;
|
||||
use Kiri\Exception\RedisConnectException;
|
||||
use Kiri\Pool\Pool;
|
||||
use RedisException;
|
||||
use function config;
|
||||
|
||||
/**
|
||||
* Class Redis
|
||||
* @package Kiri\Cache
|
||||
* @mixin \Redis
|
||||
*/
|
||||
class Redis
|
||||
{
|
||||
|
||||
public string $host = '';
|
||||
public int $port = 6379;
|
||||
public string $prefix = '';
|
||||
public string $auth = '';
|
||||
public int $databases = 0;
|
||||
public int $timeout = 30;
|
||||
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public int $read_timeout = -1;
|
||||
|
||||
/**
|
||||
* @var array|int[]
|
||||
*/
|
||||
public array $pool = ['min' => 1, 'max' => 100];
|
||||
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
Kiri::configure($this, config('redis', []));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function __call($name, $arguments): mixed
|
||||
{
|
||||
if (method_exists($this, $name)) {
|
||||
return $this->{$name}(...$arguments);
|
||||
} else {
|
||||
return $this->proxy($name, $arguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param int $timeout
|
||||
* @return bool
|
||||
* @throws
|
||||
*/
|
||||
public function waite($key, int $timeout = 5): bool
|
||||
{
|
||||
$time = time();
|
||||
while (!$this->setNx($key, '1')) {
|
||||
if (time() - $time >= $timeout) {
|
||||
return FALSE;
|
||||
}
|
||||
usleep(1000);
|
||||
}
|
||||
$this->expire($key, $timeout);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param int $timeout
|
||||
* @return bool|int
|
||||
* @throws
|
||||
*/
|
||||
public function lock($key, int $timeout = 5): bool|int
|
||||
{
|
||||
$script = <<<SCRIPT
|
||||
local _nx = redis.call('setnx',KEYS[1], ARGV[1])
|
||||
if (_nx ~= 0) then
|
||||
redis.call('expire',KEYS[1], ARGV[1])
|
||||
return 1
|
||||
end
|
||||
return 0
|
||||
SCRIPT;
|
||||
return $this->eval($script, ['{lock}:' . $key, $timeout], 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return int
|
||||
* @throws
|
||||
*/
|
||||
public function unlock($key): int
|
||||
{
|
||||
return $this->del('{lock}:' . $key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws
|
||||
*/
|
||||
public function destroy(): void
|
||||
{
|
||||
$this->pool()->close($this->host);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
* @return mixed
|
||||
* @throws
|
||||
*/
|
||||
public function proxy($name, $arguments): mixed
|
||||
{
|
||||
$client = $this->getClient();
|
||||
try {
|
||||
return $client->{$name}(...$arguments);
|
||||
} catch (\Throwable $throwable) {
|
||||
return trigger_print_error(throwable($throwable));
|
||||
} finally {
|
||||
if ($client->ping('h') == 'h') {
|
||||
$this->pool()->push($this->host, $client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \Redis
|
||||
* @throws
|
||||
*/
|
||||
private function getClient(): \Redis
|
||||
{
|
||||
return $this->pool()->get($this->host);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Pool
|
||||
* @throws
|
||||
*/
|
||||
protected function pool(): Pool
|
||||
{
|
||||
$pool = Kiri::getPool();
|
||||
if (!$pool->hasChannel($this->host)) {
|
||||
$pool->created($this->host, $this->pool['max'], [$this, 'connect']);
|
||||
}
|
||||
return $pool;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \Redis
|
||||
* @throws
|
||||
*/
|
||||
protected function connect(): \Redis
|
||||
{
|
||||
$redis = new \Redis();
|
||||
if (!$redis->connect($this->host, $this->port, $this->timeout)) {
|
||||
throw new RedisConnectException(sprintf('The Redis Connect %s::%d Fail.', $this->host, $this->port));
|
||||
}
|
||||
if (!empty($this->auth) && !$redis->auth($this->auth)) {
|
||||
throw new RedisConnectException(sprintf('Redis Error: %s, Host %s, Auth %s', $redis->getLastError(), $this->host, $this->auth));
|
||||
}
|
||||
$redis->select($this->databases);
|
||||
if ($this->read_timeout > 0) {
|
||||
$redis->setOption(\Redis::OPT_READ_TIMEOUT, $this->read_timeout);
|
||||
}
|
||||
if (!empty($this->prefix)) {
|
||||
$redis->setOption(\Redis::OPT_PREFIX, $this->prefix);
|
||||
}
|
||||
return $redis;
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Kiri;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri\Abstracts\Config;
|
||||
use Kiri\Abstracts\Input;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Kiri;
|
||||
|
||||
/**
|
||||
* Class Runtime
|
||||
* @package Kiri
|
||||
*/
|
||||
class Runtime extends Command
|
||||
{
|
||||
|
||||
|
||||
public string $command = 'runtime:builder';
|
||||
|
||||
public string $description = 'create app file cache';
|
||||
|
||||
|
||||
const CACHE_NAME = '.runtime.cache';
|
||||
const CONFIG_NAME = '.config.cache';
|
||||
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('runtime:builder');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
// TODO: Implement onHandler() method.
|
||||
$annotation = Kiri::app()->getAnnotation();
|
||||
|
||||
$runtime = storage(static::CACHE_NAME);
|
||||
$config = storage(static::CONFIG_NAME);
|
||||
|
||||
Kiri::writeFile($config, $this->configEach());
|
||||
Kiri::writeFile($runtime, serialize($annotation->getLoader()));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function configEach(): string
|
||||
{
|
||||
$array = [];
|
||||
foreach (Config::getData() as $key => $datum) {
|
||||
if ($datum instanceof \Closure) {
|
||||
continue;
|
||||
}
|
||||
if (is_array($datum)) {
|
||||
$array[$key] = $this->arrayEach($datum);
|
||||
} else {
|
||||
$array[$key] = $datum;
|
||||
}
|
||||
}
|
||||
return serialize($array);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $value
|
||||
* @return array
|
||||
*/
|
||||
private function arrayEach(array $value): array
|
||||
{
|
||||
$array = [];
|
||||
foreach ($value as $key => $item) {
|
||||
if ($item instanceof \Closure) {
|
||||
continue;
|
||||
}
|
||||
if (is_array($item)) {
|
||||
$array[$key] = $this->arrayEach($item);
|
||||
} else {
|
||||
$array[$key] = $item;
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri;
|
||||
|
||||
interface ToArray
|
||||
{
|
||||
|
||||
public function toArray();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri;
|
||||
|
||||
use Swoole\Coroutine;
|
||||
|
||||
class Waite
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param float $time
|
||||
* @return void
|
||||
*/
|
||||
public static function sleep(float $time): void
|
||||
{
|
||||
if (!class_exists(Coroutine::class) || Coroutine::getCid() > -1) {
|
||||
usleep($time * 1000);
|
||||
} else {
|
||||
Coroutine::sleep($time / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Gateway;
|
||||
|
||||
class Collector
|
||||
{
|
||||
|
||||
|
||||
public function get()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Gateway;
|
||||
|
||||
use Swoole\Http\Request;
|
||||
use Swoole\Http\Response;
|
||||
|
||||
class GatewayServer
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
*/
|
||||
public function onRequest(Request $request, Response $response)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Kiri\Gateway;
|
||||
|
||||
class HashMap
|
||||
{
|
||||
|
||||
|
||||
const HTTP = 1;
|
||||
const TCP = 2;
|
||||
const UDP = 2;
|
||||
|
||||
|
||||
public string $domain;
|
||||
|
||||
|
||||
public string $path;
|
||||
|
||||
|
||||
public string $scheme;
|
||||
|
||||
|
||||
public string $method;
|
||||
|
||||
|
||||
public string $proxy_host;
|
||||
|
||||
|
||||
public string $proxy_port;
|
||||
|
||||
|
||||
public int $type = self::HTTP;
|
||||
|
||||
|
||||
}
|
||||
@@ -1,342 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: 向林
|
||||
* Date: 2016/8/9 0009
|
||||
* Time: 17:43
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Gii;
|
||||
|
||||
use Database\Connection;
|
||||
use Database\Db;
|
||||
use Exception;
|
||||
use Kiri\Cache\Redis;
|
||||
use Kiri;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Class gii
|
||||
*
|
||||
* @package Inter\utility
|
||||
*/
|
||||
class Gii
|
||||
{
|
||||
private ?string $tableName = NULL;
|
||||
|
||||
/** @var null|Connection */
|
||||
private ?Connection $db;
|
||||
|
||||
private InputInterface $input;
|
||||
|
||||
public string $modelPath = APP_PATH . 'app/Model/';
|
||||
public string $modelNamespace = 'App\\Model\\';
|
||||
|
||||
public string $controllerPath = APP_PATH . 'app/Http/Controller/';
|
||||
public string $controllerNamespace = 'App\\Controller\\';
|
||||
|
||||
|
||||
public static array $createSqls = [];
|
||||
|
||||
|
||||
public array $keyword = [
|
||||
'ADD', 'ALL', 'ALTER', 'AND', 'AS', 'ASC', 'ASENSITIVE', 'BEFORE', 'BETWEEN', 'BIGINT', 'BINARY', 'BLOB', 'BOTH', 'BY', 'CALL', 'CASCADE', 'CASE', 'CHANGE', 'CHAR', 'CHARACTER', 'CHECK', 'COLLATE', 'COLUMN', 'CONDITION', 'CONNECTION', 'CONSTRAINT', 'CONTINUE', 'CONVERT', 'CREATE', 'CROSS', 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'CURRENT_USER', 'CURSOR', 'DATABASE', 'DATABASES', 'DAY_HOUR', 'DAY_MICROSECOND', 'DAY_MINUTE', 'DAY_SECOND', 'DEC', 'DECIMAL', 'DECLARE', 'DEFAULT', 'DELAYED', 'DELETE', 'DESC', 'DESCRIBE', 'DETERMINISTIC', 'DISTINCT', 'DISTINCTROW', 'DIV', 'DOUBLE', 'DROP', 'DUAL', 'EACH', 'ELSE', 'ELSEIF', 'ENCLOSED', 'ESCAPED', 'EXISTS', 'EXIT', 'EXPLAIN', 'FALSE', 'FETCH', 'FLOAT', 'FLOAT4', 'FLOAT8', 'FOR', 'FORCE', 'FOREIGN', 'FROM', 'FULLTEXT', 'GOTO', 'GRANT', 'GROUP', 'HAVING', 'HIGH_PRIORITY', 'HOUR_MICROSECOND', 'HOUR_MINUTE', 'HOUR_SECOND', 'IF', 'IGNORE', 'IN', 'INDEX', 'INFILE', 'INNER', 'INOUT', 'INSENSITIVE', 'INSERT', 'INT', 'INT1', 'INT2', 'INT3', 'INT4', 'INT8', 'INTEGER', 'INTERVAL', 'INTO', 'IS', 'ITERATE', 'JOIN', 'KEY', 'KEYS', 'KILL', 'LABEL', 'LEADING', 'LEAVE', 'LEFT', 'LIKE', 'LIMIT', 'LINEAR', 'LINES', 'LOAD', 'LOCALTIME', 'LOCALTIMESTAMP', 'LOCK', 'LONG', 'LONGBLOB', 'LONGTEXT', 'LOOP', 'LOW_PRIORITY', 'MATCH', 'MEDIUMBLOB', 'MEDIUMINT', 'MEDIUMTEXT', 'MIDDLEINT', 'MINUTE_MICROSECOND', 'MINUTE_SECOND', 'MOD', 'MODIFIES', 'NATURAL', 'NOT', 'NO_WRITE_TO_BINLOG', 'NULL', 'NUMERIC', 'ON', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', 'OR', 'ORDER', 'OUT', 'OUTER', 'OUTFILE', 'PRECISION', 'PRIMARY', 'PROCEDURE', 'PURGE', 'RAID0', 'RANGE', 'READ', 'READS', 'REAL', 'REFERENCES', 'REGEXP', 'RELEASE', 'RENAME', 'REPEAT', 'REPLACE', 'REQUIRE', 'RESTRICT', 'RETURN', 'REVOKE', 'RIGHT', 'RLIKE', 'SCHEMA', 'SCHEMAS', 'SECOND_MICROSECOND', 'SELECT', 'SENSITIVE', 'SEPARATOR', 'SET', 'SHOW', 'SMALLINT', 'SPATIAL', 'SPECIFIC', 'SQL', 'SQLEXCEPTION', 'SQLSTATE', 'SQLWARNING', 'SQL_BIG_RESULT', 'SQL_CALC_FOUND_ROWS', 'SQL_SMALL_RESULT', 'SSL', 'STARTING', 'STRAIGHT_JOIN', 'TABLE', 'TERMINATED', 'THEN', 'TINYBLOB', 'TINYINT', 'TINYTEXT', 'TO', 'TRAILING', 'TRIGGER', 'TRUE', 'UNDO', 'UNION', 'UNIQUE', 'UNLOCK', 'UNSIGNED', 'UPDATE', 'USAGE', 'USE', 'USING', 'UTC_DATE', 'UTC_TIME', 'UTC_TIMESTAMP', 'VALUES', 'VARBINARY', 'VARCHAR', 'VARCHARACTER', 'VARYING', 'WHEN', 'WHERE', 'WHILE', 'WITH', 'WRITE', 'X509', 'XOR', 'YEAR_MONTH', 'ZEROFILL'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param Connection|null $db
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function run(?Connection $db, InputInterface $input): array
|
||||
{
|
||||
return $this->gen($input, $db);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param $db
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function gen(InputInterface $input, $db): array
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->db = $db;
|
||||
|
||||
$make = $this->input->getOption('make');
|
||||
if (empty($make)) {
|
||||
throw new Exception('构建类型不能为空~');
|
||||
}
|
||||
switch (strtolower($make)) {
|
||||
case 'task':
|
||||
$task = new GiiTask();
|
||||
$task->setInput($this->input);
|
||||
return $task->generate();
|
||||
case 'middleware':
|
||||
$task = new GiiMiddleware();
|
||||
$task->setInput($this->input);
|
||||
return $task->generate();
|
||||
case 'rpc-client':
|
||||
$task = new GiiRpcClient();
|
||||
$task->setInput($this->input);
|
||||
return $task->generate();
|
||||
case 'rpc-service':
|
||||
$task = new GiiRpcService();
|
||||
$task->setInput($this->input);
|
||||
return $task->generate();
|
||||
case 'json-rpc':
|
||||
$task = new GiiJsonRpc();
|
||||
$task->setInput($this->input);
|
||||
return $task->create();
|
||||
default:
|
||||
return $this->getModel($make, $input);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $make
|
||||
* @param $input
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getModel($make, $input): array
|
||||
{
|
||||
return $this->makeByDatabases($make, $input);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $make
|
||||
* @param InputInterface $input
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function makeByDatabases($make, InputInterface $input): array
|
||||
{
|
||||
if ($input->hasOption('name')) {
|
||||
$this->tableName = $input->getOption('name');
|
||||
}
|
||||
return match ($make) {
|
||||
'controller' => $this->getTable(1, 0),
|
||||
'model' => $this->getTable(0, 1),
|
||||
default => [],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $controller
|
||||
* @param $model
|
||||
* @return array
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getTable($controller, $model): array
|
||||
{
|
||||
$tables = $this->getFields($this->getTables());
|
||||
if (empty($tables)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$fileList = [];
|
||||
foreach ($tables as $key => $val) {
|
||||
$data = $this->createModelFile($key, $val);
|
||||
if ($controller == 1) {
|
||||
$fileList[] = $this->generateController($data);
|
||||
}
|
||||
if ($model == 1) {
|
||||
$fileList[] = $this->generateModel($data);
|
||||
}
|
||||
}
|
||||
return $fileList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
private function generateModel(array $data): string
|
||||
{
|
||||
$controller = new GiiModel($data['classFileName'], $data['tableName'], $data['visible'], $data['res'], $data['fields']);
|
||||
$controller->setConnection($this->db);
|
||||
$controller->setModelPath($this->modelPath);
|
||||
$controller->setModelNamespace($this->modelNamespace);
|
||||
$controller->setInput($this->input);
|
||||
// $controller->setModule($this->input->getArgument('module'));
|
||||
$controller->setControllerPath($this->controllerPath);
|
||||
$controller->setControllerNamespace($this->controllerNamespace);
|
||||
return $controller->generate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
private function generateController(array $data): string
|
||||
{
|
||||
$controller = new GiiController($data['classFileName'], $data['fields']);
|
||||
$controller->setConnection($this->db);
|
||||
$controller->setModelPath($this->modelPath);
|
||||
$controller->setInput($this->input);
|
||||
$controller->setModelNamespace($this->modelNamespace);
|
||||
$controller->setControllerPath($this->controllerPath);
|
||||
$controller->setModule($this->input->getArgument('module'));
|
||||
$controller->setControllerNamespace($this->controllerNamespace);
|
||||
return $controller->generate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getTables(): array|string|null
|
||||
{
|
||||
if (empty($this->tableName)) {
|
||||
return $this->showAll();
|
||||
}
|
||||
$res = $this->tableName;
|
||||
if (is_string($res)) {
|
||||
$res = explode(',', $this->tableName);
|
||||
}
|
||||
if (empty($res)) {
|
||||
return [];
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function showAll(): array
|
||||
{
|
||||
$res = [];
|
||||
$_tables = Db::findAllBySql('show tables from `' . $this->db->database . '`', [], $this->db);
|
||||
if (empty($_tables)) {
|
||||
return $res;
|
||||
}
|
||||
foreach ($_tables as $key => $val) {
|
||||
$res[] = array_shift($val);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
* @return bool|int|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getIndex($table): bool|int|null
|
||||
{
|
||||
$data = Db::findAllBySql('SHOW INDEX FROM ' . $table, [], $this->db);
|
||||
|
||||
return empty($data) ? NULL : $data[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $tables
|
||||
*
|
||||
* @return array
|
||||
* @throws
|
||||
*/
|
||||
private function getFields($tables): array
|
||||
{
|
||||
$res = [];
|
||||
if (!is_array($tables)) {
|
||||
$tables = [$tables];
|
||||
}
|
||||
foreach ($tables as $key => $val) {
|
||||
if (empty($val)) continue;
|
||||
$_tmp = Db::findAllBySql('SHOW FULL FIELDS FROM `' . $this->db->database . '`.' . $val, [], $this->db);
|
||||
if (empty($_tmp)) {
|
||||
continue;
|
||||
}
|
||||
$res[$val] = $_tmp;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $tableName
|
||||
* @param $tables
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function createModelFile($tableName, $tables): array
|
||||
{
|
||||
$res = $visible = $fields = $keys = [];
|
||||
foreach ($tables as $_key => $_val) {
|
||||
$keys = $tableName;
|
||||
if ($_val['Extra'] == 'auto_increment' || $_val['Key'] == 'PRI') {
|
||||
$keys = $tableName;
|
||||
}
|
||||
if (!isset($keys) && !($index = $this->getIndex($tableName))) {
|
||||
$keys = $index['Column_name'];
|
||||
}
|
||||
if (in_array(strtoupper($_val['Field']), $this->keyword)) {
|
||||
throw new Exception('You can not use keyword "' . $_val['Field'] . '" as field at table "' . $tableName . '"');
|
||||
}
|
||||
array_push($visible, $this->createVisible($_val['Field']));
|
||||
array_push($fields, $_val);
|
||||
$res[] = $this->createSetFunc($_val['Field'], $_val['Comment']);
|
||||
}
|
||||
|
||||
$classFileName = $this->getClassName($tableName);
|
||||
|
||||
return [
|
||||
'classFileName' => $classFileName,
|
||||
'tableName' => $keys,
|
||||
'visible' => $visible,
|
||||
'fields' => $fields,
|
||||
'res' => $res,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $field
|
||||
* @return string
|
||||
* 创建变量注释
|
||||
*/
|
||||
private function createVisible($field): string
|
||||
{
|
||||
return '
|
||||
* @property $' . $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $field
|
||||
* @param $comment
|
||||
* @return string
|
||||
* 暂时不知道干嘛用的
|
||||
*/
|
||||
private function createSetFunc($field, $comment): string
|
||||
{
|
||||
return '
|
||||
' . str_pad('\'' . $field . '\'', 20, ' ', STR_PAD_RIGHT) . '=> \'' . (empty($comment) ? ucfirst($field) : $comment) . '\',';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $tableName
|
||||
* @return string
|
||||
* 构建类名称
|
||||
*/
|
||||
private function getClassName($tableName): string
|
||||
{
|
||||
$res = [];
|
||||
$tableName = str_replace($this->db->tablePrefix,'', $tableName);
|
||||
foreach (explode('_', $tableName) as $n => $val) {
|
||||
$res[] = ucfirst($val);
|
||||
}
|
||||
return implode('', $res);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,411 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Gii;
|
||||
|
||||
|
||||
use Database\Connection;
|
||||
use Exception;
|
||||
use Kiri\Core\Json;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Class GiiBase
|
||||
* @package Gii
|
||||
*/
|
||||
abstract class GiiBase
|
||||
{
|
||||
|
||||
public array $fileList = [];
|
||||
|
||||
|
||||
protected InputInterface $input;
|
||||
|
||||
public string $modelPath = APP_PATH . 'app/Model/';
|
||||
public string $modelNamespace = 'App\Model\\';
|
||||
|
||||
public string $controllerPath = APP_PATH . 'app/Http/Controller/';
|
||||
public string $controllerNamespace = 'App\\Controller\\';
|
||||
|
||||
public ?string $module = null;
|
||||
|
||||
public array $rules = [];
|
||||
public array $type = [
|
||||
'int' => ['tinyint', 'smallint', 'mediumint', 'int', 'bigint'],
|
||||
'string' => ['char', 'varchar', 'tinytext', 'text', 'mediumtext', 'longtext', 'enum'],
|
||||
'date' => ['date'],
|
||||
'time' => ['time'],
|
||||
'year' => ['year'],
|
||||
'datetime' => ['datetime'],
|
||||
'timestamp' => ['timestamp'],
|
||||
'float' => ['float', 'double', 'decimal',],
|
||||
];
|
||||
public ?string $tableName = NULL;
|
||||
|
||||
public ?Connection $db = null;
|
||||
|
||||
/**
|
||||
* @param string $modelPath
|
||||
*/
|
||||
public function setModelPath(string $modelPath): void
|
||||
{
|
||||
$this->modelPath = $modelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $modelNamespace
|
||||
*/
|
||||
public function setModelNamespace(string $modelNamespace): void
|
||||
{
|
||||
$this->modelNamespace = $modelNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $controllerPath
|
||||
*/
|
||||
public function setControllerPath(string $controllerPath): void
|
||||
{
|
||||
$this->controllerPath = $controllerPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $module
|
||||
*/
|
||||
public function setModule($module)
|
||||
{
|
||||
$this->module = $module;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $controllerNamespace
|
||||
*/
|
||||
public function setControllerNamespace(string $controllerNamespace): void
|
||||
{
|
||||
$this->controllerNamespace = $controllerNamespace;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
*/
|
||||
public function setInput(InputInterface $input)
|
||||
{
|
||||
$this->input = $input;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $object
|
||||
* @param $className
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUseContent(ReflectionClass $object, $className): string
|
||||
{
|
||||
if (empty($object)) {
|
||||
return '';
|
||||
}
|
||||
$file = $this->getFilePath($className);
|
||||
if (!file_exists($file)) {
|
||||
return '';
|
||||
}
|
||||
$content = file_get_contents($file);
|
||||
$explode = explode(PHP_EOL, $content);
|
||||
$exists = array_slice($explode, 0, $object->getStartLine());
|
||||
$_tmp = [];
|
||||
foreach ($exists as $key => $val) {
|
||||
if (trim($val) == '/**') {
|
||||
break;
|
||||
}
|
||||
$_tmp[] = $val;
|
||||
}
|
||||
return trim(implode(PHP_EOL, $_tmp));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $fileName
|
||||
* @param ReflectionClass $class
|
||||
* @return string
|
||||
*/
|
||||
protected function getImports(string $fileName, ReflectionClass $class): string
|
||||
{
|
||||
$startLine = 1;
|
||||
$array = [];
|
||||
$fileOpen = fopen($fileName, 'r');
|
||||
while (($content = fgets($fileOpen)) !== false) {
|
||||
if (str_starts_with($content, 'use ')) {
|
||||
$array[] = $content;
|
||||
}
|
||||
if ($startLine == $class->getStartLine()) {
|
||||
break;
|
||||
}
|
||||
++$startLine;
|
||||
}
|
||||
return implode($array);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
* @return string
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
protected function getClassProperty(ReflectionClass $class): string
|
||||
{
|
||||
$html = '';
|
||||
|
||||
$rc = $class->getParentClass()->getConstants();
|
||||
|
||||
foreach ($class->getConstants() as $key => $val) {
|
||||
if (isset($rc[$key])) {
|
||||
continue;
|
||||
}
|
||||
if (is_numeric($val)) {
|
||||
$html .= '
|
||||
const ' . $key . ' = ' . $val . ';' . "\n";
|
||||
} else {
|
||||
$html .= '
|
||||
const ' . $key . ' = \'' . $val . '\';' . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($class->getDefaultProperties() as $key => $val) {
|
||||
$property = $class->getProperty($key);
|
||||
if ($key == 'primary' || $key == 'table' || $key == 'connection' || $key == 'rules') {
|
||||
continue;
|
||||
}
|
||||
if ($property->class != $class->getName()) continue;
|
||||
if (is_array($val)) {
|
||||
$val = '[\'' . implode('\', \'', $val) . '\']';
|
||||
} else if (!is_numeric($val)) {
|
||||
$val = '\'' . $val . '\'';
|
||||
}
|
||||
|
||||
if ($property->isProtected()) {
|
||||
$debug = 'protected';
|
||||
} else if ($property->isPrivate()) {
|
||||
$debug = 'private';
|
||||
} else {
|
||||
$debug = 'public';
|
||||
}
|
||||
if ($property->hasType()) {
|
||||
$type = ' ' . $property->getType() . ' $' . $key . ' = ' . $val . ';' . "\n";
|
||||
} else {
|
||||
$type = ' $' . $key . ' = ' . $val . ';' . "\n";
|
||||
}
|
||||
if ($property->isStatic()) {
|
||||
$html .= '
|
||||
' . $debug . ' static' . $type;
|
||||
} else {
|
||||
$html .= '
|
||||
' . $debug . $type;
|
||||
}
|
||||
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $class
|
||||
* @param array $filters
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function getClassMethods(ReflectionClass $class, array $filters = []): string
|
||||
{
|
||||
$methods = $class->getMethods();
|
||||
|
||||
$classFileName = str_replace(APP_PATH, '', $class->getFileName());
|
||||
|
||||
$content = [];
|
||||
if (!empty($methods)) foreach ($methods as $key => $val) {
|
||||
if ($val->class != $class->getName()) continue;
|
||||
if (in_array($val->name, $filters)) continue;
|
||||
$over = "
|
||||
" . $val->getDocComment() . "\n";
|
||||
|
||||
$attributes = $val->getAttributes();
|
||||
if (!empty($attributes)) {
|
||||
foreach ($attributes as $attribute) {
|
||||
$explode = explode('\\', $attribute->getName());
|
||||
|
||||
$_array = [];
|
||||
foreach ($attribute->getArguments() as $_key => $argument) {
|
||||
$argument = $this->resolveArray($argument);
|
||||
if (is_numeric($_key)) {
|
||||
$_array[] = $argument;
|
||||
} else {
|
||||
$_array[] = $_key . ': ' . $argument . '';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($_array)) {
|
||||
$end = " #[" . end($explode) . "]
|
||||
";
|
||||
} else {
|
||||
$end = " #[" . end($explode) . "(" . implode(',', $_array) . ")]
|
||||
";
|
||||
}
|
||||
if (str_contains($over, $end)) {
|
||||
$over = str_replace($end, '', $over);
|
||||
}
|
||||
$over .= $end;
|
||||
}
|
||||
}
|
||||
|
||||
$func = $this->getFuncLineContent($class, $classFileName, $val->name) . "\n";
|
||||
|
||||
$content[] = $over . $func;
|
||||
}
|
||||
return implode(PHP_EOL, $content);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $argument
|
||||
* @return string
|
||||
*/
|
||||
private function resolveArray($argument): string
|
||||
{
|
||||
if (is_array($argument)) {
|
||||
$__array = [];
|
||||
foreach ($argument as $key => $value) {
|
||||
if (is_string($value)) {
|
||||
if (str_contains($value, '\\') && class_exists($value)) {
|
||||
$explode_class = explode('\\', $value);
|
||||
|
||||
$__array[] = end($explode_class) . '::class';
|
||||
} else {
|
||||
$__array[] = '\'' . $value . '\'';
|
||||
}
|
||||
} else {
|
||||
$value = str_replace('{', '[', Json::encode($value));
|
||||
$value = str_replace('}', ']', Json::encode($value));
|
||||
$value = str_replace(':', '=>', Json::encode($value));
|
||||
|
||||
$value = preg_replace('/"\d+"\=\>/', '', $value);
|
||||
|
||||
$__array[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$argument = '[' . implode(', ', $__array) . ']';
|
||||
} else {
|
||||
$argument = '\'' . $argument . '\'';
|
||||
}
|
||||
return $argument;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $fields
|
||||
* @return mixed 返回表主键
|
||||
* 返回表主键
|
||||
*/
|
||||
public function getPrimaryKey($fields): mixed
|
||||
{
|
||||
$condition = ['PRI', 'UNI'];
|
||||
foreach ($fields as $field) {
|
||||
if ($field['Extra'] == 'auto_increment') {
|
||||
return $field['Field'];
|
||||
}
|
||||
if (in_array($field['Key'], $condition)) {
|
||||
return $field['Field'];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $className
|
||||
* @return string
|
||||
*/
|
||||
private function getFilePath($className): string
|
||||
{
|
||||
if (strpos($className, '\\')) {
|
||||
$className = str_replace('\\', '/', $className);
|
||||
}
|
||||
if (strpos($className, '\\')) {
|
||||
$className = str_replace('\\', '/', $className);
|
||||
}
|
||||
|
||||
return APP_PATH . $className;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReflectionClass $object
|
||||
* @param $className
|
||||
* @param $method
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getFuncLineContent(ReflectionClass $object, $className, $method): string
|
||||
{
|
||||
$fun = $object->getMethod($method);
|
||||
|
||||
$content = file_get_contents($this->getFilePath($className));
|
||||
$explode = explode(PHP_EOL, $content);
|
||||
$exists = array_slice($explode, $fun->getStartLine() - 1, $fun->getEndLine() - $fun->getStartLine() + 1);
|
||||
return implode(PHP_EOL, $exists);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getModelPath(): array
|
||||
{
|
||||
$dbName = $this->db->id;
|
||||
if (empty($dbName) || $dbName == 'db') {
|
||||
$dbName = '';
|
||||
}
|
||||
|
||||
$modelPath = [
|
||||
'namespace' => $this->modelNamespace,
|
||||
'path' => $this->modelPath,
|
||||
];
|
||||
if (!is_dir($modelPath['path'])) {
|
||||
mkdir($modelPath['path']);
|
||||
}
|
||||
if (!empty($dbName)) {
|
||||
$modelPath['namespace'] = $this->modelNamespace . ucfirst($dbName);
|
||||
$modelPath['path'] = $this->modelPath . ucfirst($dbName);
|
||||
}
|
||||
|
||||
if (!is_dir($modelPath['path'])) {
|
||||
mkdir($modelPath['path']);
|
||||
}
|
||||
return $modelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $db
|
||||
*/
|
||||
public function setConnection($db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $val
|
||||
* @return string
|
||||
*/
|
||||
protected function checkIsRequired($val): string
|
||||
{
|
||||
return strtolower($val['Null']) == 'no' && $val['Default'] === NULL ? 'true' : 'false';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFileLists(): array
|
||||
{
|
||||
return $this->fileList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Gii;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Kiri\Abstracts\Config;
|
||||
use Kiri\Exception\ConfigException;
|
||||
use Kiri;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Class Command
|
||||
* @package Http
|
||||
*/
|
||||
class GiiCommand extends Command
|
||||
{
|
||||
|
||||
public string $command = 'sw:gii';
|
||||
|
||||
|
||||
public string $description = './snowflake sw:gii make=model|controller|task|interceptor|limits|middleware name=xxxx';
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('sw:gii')
|
||||
->addOption('make','m', InputArgument::OPTIONAL)
|
||||
->addOption('name','t', InputArgument::OPTIONAL)
|
||||
->addOption('databases','d', InputArgument::OPTIONAL)
|
||||
->setDescription('./snowflake sw:gii make=model|controller|task|interceptor|limits|middleware name=xxxx');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
* @throws ConfigException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
/** @var Gii $gii */
|
||||
$gii = Kiri::app()->get('gii');
|
||||
|
||||
$connections = Kiri::app()->get('db');
|
||||
if (($db = $input->getOption('databases')) != null) {
|
||||
$gii->run($connections->get($db), $input);
|
||||
return 1;
|
||||
}
|
||||
|
||||
$action = $input->getOption('make');
|
||||
if (!in_array($action, ['model', 'controller'])) {
|
||||
$gii->run(null, $input);
|
||||
return 1;
|
||||
}
|
||||
|
||||
$array = [];
|
||||
foreach (Config::get('databases.connections') as $key => $connection) {
|
||||
$array[$key] = $gii->run($connections->get($key), $input);
|
||||
}
|
||||
|
||||
$output->writeln(json_encode($array, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,536 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Gii;
|
||||
|
||||
use Exception;
|
||||
use ReflectionException;
|
||||
use Kiri;
|
||||
|
||||
/**
|
||||
* Class GiiController
|
||||
* @package Gii
|
||||
*/
|
||||
class GiiController extends GiiBase
|
||||
{
|
||||
|
||||
public string $className = '';
|
||||
|
||||
public array $fields = [];
|
||||
|
||||
|
||||
/**
|
||||
* GiiController constructor.
|
||||
* @param $className
|
||||
* @param $fields
|
||||
*/
|
||||
public function __construct($className, $fields)
|
||||
{
|
||||
$this->className = $className;
|
||||
$this->fields = $fields;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string|bool
|
||||
* @throws ReflectionException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function generate(): string|bool
|
||||
{
|
||||
$path = $this->getControllerPath();
|
||||
$modelPath = $this->getModelPath();
|
||||
|
||||
$managerName = $this->className;
|
||||
|
||||
$namespace = rtrim($path['namespace'], '\\');
|
||||
$model_namespace = rtrim($modelPath['namespace'], '\\');
|
||||
|
||||
$class = '';
|
||||
$controller = str_replace('\\\\', '\\', "$namespace\\{$managerName}Controller");
|
||||
|
||||
$html = "<?php
|
||||
namespace {$namespace};
|
||||
|
||||
";
|
||||
if (file_exists($path['path'] . '/' . $managerName . 'Controller.php')) {
|
||||
try {
|
||||
$class = new \ReflectionClass($controller);
|
||||
|
||||
$import = $this->getImports($path['path'] . '/' . $managerName . 'Controller.php', $class);
|
||||
} catch (\Throwable $Exception) {
|
||||
exit(logger()->addError($Exception, 'throwable'));
|
||||
}
|
||||
} else {
|
||||
$import = "use Kiri;
|
||||
use Exception;
|
||||
use Kiri\Annotation\Target;
|
||||
use Kiri\Annotation\Route\Middleware;
|
||||
use Kiri\Annotation\Route\Route;
|
||||
use Kiri\Core\Str;
|
||||
use Kiri\Core\Json;
|
||||
use Kiri\Message\Context\Request;
|
||||
use Kiri\Message\Context\Response;
|
||||
use Kiri\Message\Controller;
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use {$model_namespace}\\{$managerName};
|
||||
";
|
||||
}
|
||||
if (!empty($import)) {
|
||||
$html .= $import;
|
||||
}
|
||||
|
||||
$controllerName = $managerName;
|
||||
|
||||
$historyModel = "use {$model_namespace}\\{$managerName};";
|
||||
if (!str_contains($html, $historyModel)) {
|
||||
$html .= $historyModel;
|
||||
}
|
||||
|
||||
$html .= "
|
||||
|
||||
/**
|
||||
* Class {$controllerName}Controller
|
||||
*
|
||||
* @package controller
|
||||
*/
|
||||
#[Target] class {$controllerName}Controller extends Controller
|
||||
{
|
||||
|
||||
";
|
||||
|
||||
|
||||
$funcNames = [];
|
||||
if (is_object($class)) {
|
||||
$html .= $this->getClassProperty($class);
|
||||
$html .= $this->getClassMethods($class);
|
||||
}
|
||||
|
||||
$default = ['loadParam', 'actionAdd', 'actionUpdate', 'actionDetail', 'actionDelete', 'actionBatchDelete', 'actionList'];
|
||||
|
||||
foreach ($default as $key => $val) {
|
||||
if (str_contains($html, ' function ' . $val . '(')) {
|
||||
continue;
|
||||
}
|
||||
$html .= $this->{'controllerMethod' . str_replace('action', '', $val)}($this->fields, $managerName, $managerName, $path) . "\n";
|
||||
}
|
||||
|
||||
$html .= '
|
||||
}';
|
||||
|
||||
$file = $path['path'] . '/' . $controllerName . 'Controller.php';
|
||||
if (file_exists($file)) {
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
Kiri::writeFile($file, $html);
|
||||
return $controllerName . 'Controller.php';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getControllerPath(): array
|
||||
{
|
||||
$dbName = $this->db->id;
|
||||
if (empty($dbName) || $dbName == 'db') {
|
||||
$dbName = '';
|
||||
}
|
||||
|
||||
$module = empty($this->module) ? '' : $this->module;
|
||||
$modelPath['namespace'] = $this->controllerNamespace . $module;
|
||||
$modelPath['path'] = $this->controllerPath . $module;
|
||||
if (!is_dir($modelPath['path'])) {
|
||||
mkdir($modelPath['path']);
|
||||
}
|
||||
if (!empty($dbName)) {
|
||||
$modelPath['namespace'] = $this->controllerNamespace . ucfirst($dbName);
|
||||
$modelPath['path'] = $this->controllerPath . ucfirst($dbName);
|
||||
}
|
||||
|
||||
$modelPath['namespace'] = rtrim($modelPath['namespace'], '\\');
|
||||
$modelPath['path'] = rtrim($modelPath['path'], '\\');
|
||||
|
||||
if (!is_dir($modelPath['path'])) {
|
||||
mkdir($modelPath['path']);
|
||||
}
|
||||
return $modelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fields
|
||||
* @param $className
|
||||
* @param null $object
|
||||
* @param $path
|
||||
* @return string
|
||||
* 新增
|
||||
*/
|
||||
public function controllerMethodAdd($fields, $className, $object, $path): string
|
||||
{
|
||||
$_path = str_replace(CONTROLLER_PATH, '', $path['path']);
|
||||
$_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className);
|
||||
|
||||
$_path = ltrim($_path,'/');
|
||||
|
||||
return '
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
#[Route(uri: "' . $_path . '/add", method: "POST")]
|
||||
#[Middleware(middleware: [])]
|
||||
public function actionAdd(): string
|
||||
{
|
||||
$model = new ' . $className . '();
|
||||
$model->attributes = $this->loadParam();
|
||||
if (!$model->save()) {
|
||||
return JSON::to(500, $model->getLastError());
|
||||
}
|
||||
return JSON::to(0, $model->toArray());
|
||||
}';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fields
|
||||
* @param $className
|
||||
* @param null $object
|
||||
* @return string
|
||||
* 通用
|
||||
*/
|
||||
public function controllerMethodLoadParam($fields, $className, $object = NULL): string
|
||||
{
|
||||
return '
|
||||
/**
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
#[ArrayShape([])]
|
||||
private function loadParam(): array
|
||||
{
|
||||
return [' . $this->getData($fields) . '
|
||||
];
|
||||
}';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fields
|
||||
* @param $className
|
||||
* @param null $object
|
||||
* @param array $path
|
||||
* @return string
|
||||
* 构建更新
|
||||
*/
|
||||
public function controllerMethodUpdate($fields, $className, $object = NULL, $path = []): string
|
||||
{
|
||||
$_path = str_replace(CONTROLLER_PATH, '', $path['path']);
|
||||
$_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className);
|
||||
|
||||
$_path = ltrim($_path,'/');
|
||||
|
||||
return '
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
#[Route(uri: "' . $_path . '/update", method: "POST")]
|
||||
#[Middleware(middleware: [])]
|
||||
public function actionUpdate(): string
|
||||
{
|
||||
$model = ' . $className . '::findOne($this->request->post(\'id\', 0));
|
||||
if (empty($model)) {
|
||||
return JSON::to(500, SELECT_IS_NULL);
|
||||
}
|
||||
$model->attributes = $this->loadParam();
|
||||
|
||||
if (!$model->save()) {
|
||||
return JSON::to(500, $model->getLastError());
|
||||
}
|
||||
return JSON::to(0, $model->toArray());
|
||||
}';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fields
|
||||
* @param $className
|
||||
* @param null $object
|
||||
* @param array $path
|
||||
* @return string
|
||||
* 构建更新
|
||||
*/
|
||||
public function controllerMethodBatchDelete($fields, $className, $object = NULL, $path = []): string
|
||||
{
|
||||
$_path = str_replace(CONTROLLER_PATH, '', $path['path']);
|
||||
$_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className);
|
||||
|
||||
$_path = ltrim($_path,'/');
|
||||
|
||||
return '
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
#[Route(uri: "' . $_path . '/batch-delete", method: "POST")]
|
||||
#[Middleware(middleware: [])]
|
||||
public function actionBatchDelete(): string
|
||||
{
|
||||
$_key = $this->request->array(\'ids\');
|
||||
if (empty($_key)) {
|
||||
return JSON::to(500, PARAMS_IS_NULL);
|
||||
}
|
||||
|
||||
$model = ' . $className . '::find()->whereIn(\'id\', $_key);
|
||||
if (!$model->delete()) {
|
||||
return JSON::to(500, DB_ERROR_BUSY);
|
||||
}
|
||||
return JSON::to(0, $_key);
|
||||
}';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fields
|
||||
* @param $className
|
||||
* @param $managerName
|
||||
* @param array $path
|
||||
* @return string
|
||||
* 构建详情
|
||||
*/
|
||||
public function controllerMethodDetail($fields, $className, $managerName, $path = []): string
|
||||
{
|
||||
$_path = str_replace(CONTROLLER_PATH, '', $path['path']);
|
||||
$_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className);
|
||||
|
||||
$_path = ltrim($_path,'/');
|
||||
|
||||
return '
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
#[Route(uri: "' . $_path . '/detail", method: "POST")]
|
||||
#[Middleware(middleware: [])]
|
||||
public function actionDetail(): string
|
||||
{
|
||||
$model = ' . $managerName . '::findOne($this->request->query(\'id\'));
|
||||
if (empty($model)) {
|
||||
return JSON::to(404, SELECT_IS_NULL);
|
||||
}
|
||||
return JSON::to(0, $model->toArray());
|
||||
}';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fields
|
||||
* @param $className
|
||||
* @param $managerName
|
||||
* @param $path
|
||||
* @return string
|
||||
* 构建删除操作
|
||||
*/
|
||||
public function controllerMethodDelete($fields, $className, $managerName, $path): string
|
||||
{
|
||||
$_path = str_replace(CONTROLLER_PATH, '', $path['path']);
|
||||
$_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className);
|
||||
|
||||
$_path = ltrim($_path,'/');
|
||||
|
||||
return '
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
#[Route(uri: "' . $_path . '/delete", method: "POST")]
|
||||
#[Middleware(middleware: [])]
|
||||
public function actionDelete(): string
|
||||
{
|
||||
$_key = $this->request->int(\'id\', true);
|
||||
|
||||
$model = ' . $managerName . '::findOne($_key);
|
||||
if (empty($model)) {
|
||||
return JSON::to(500, SELECT_IS_NULL);
|
||||
}
|
||||
if (!$model->delete()) {
|
||||
return JSON::to(500, $model->getLastError());
|
||||
}
|
||||
return JSON::to(0, $model);
|
||||
}';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fields
|
||||
* @param $className
|
||||
* @param $managerName
|
||||
* @param array $path
|
||||
* @return string
|
||||
* 构建查询列表
|
||||
*/
|
||||
public function controllerMethodList($fields, $className, $managerName, $path = []): string
|
||||
{
|
||||
$_path = str_replace(CONTROLLER_PATH, '', $path['path']);
|
||||
$_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className);
|
||||
|
||||
|
||||
$_path = ltrim($_path,'/');
|
||||
|
||||
return '
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
#[Route(uri: "' . $_path . '/list", method: "POST")]
|
||||
#[Middleware(middleware: [])]
|
||||
public function actionList(): string
|
||||
{
|
||||
//分页处理
|
||||
$count = $this->request->query(\'count\', -1);
|
||||
$order = $this->request->query(\'order\', \'id\');
|
||||
if (!empty($order)) {
|
||||
$order .= !$this->request->query(\'isDesc\', 0) ? \' asc\' : \' desc\';
|
||||
} else {
|
||||
$order = \'id desc\';
|
||||
}
|
||||
|
||||
//列表输出
|
||||
$model = ' . $managerName . '::find()->where($this->request->gets())->orderBy($order);
|
||||
|
||||
$keyword = $this->request->query(\'keyword\', null);
|
||||
if (!empty($keyword)) {
|
||||
$model->like(\'keyword\', $keyword);
|
||||
}
|
||||
|
||||
if ((int) $count === 1) {
|
||||
$count = $model->count();
|
||||
}
|
||||
if ($count != -100) {
|
||||
$model->limit($this->request->offset() ,$this->request->size());
|
||||
}
|
||||
|
||||
$data = $model->all()->toArray();
|
||||
|
||||
return JSON::to(0, $data, $count);
|
||||
}
|
||||
';
|
||||
}
|
||||
|
||||
private function getData($fields): string
|
||||
{
|
||||
$html = '';
|
||||
|
||||
$length = $this->getMaxLength($fields);
|
||||
|
||||
|
||||
foreach ($fields as $key => $val) {
|
||||
preg_match('/\((\d+)(,(\d+))*\)/', $val['Type'], $number);
|
||||
$type = strtolower(preg_replace('/\(\d+(,\d+)*\)/', '', $val['Type']));
|
||||
|
||||
$first = preg_replace('/\s+\w+/', '', $type);
|
||||
if ($val['Field'] == 'id') continue;
|
||||
if ($type == 'timestamp') continue;
|
||||
$_field = [];
|
||||
$_field['required'] = $this->checkIsRequired($val);
|
||||
foreach ($this->type as $_key => $value) {
|
||||
if (!in_array(strtolower($first), $value)) continue;
|
||||
$comment = '//' . $val['Comment'];
|
||||
$_field['type'] = $_key;
|
||||
|
||||
if ($type == 'date' || $type == 'datetime' || $type == 'time') {
|
||||
$_tps = match ($type) {
|
||||
'date' => '$this->request->' . $_key . '(\'' . $val['Field'] . '\', date(\'Y-m-d\'))',
|
||||
'time' => '$this->request->' . $_key . '(\'' . $val['Field'] . '\', date(\'H:i:s\'))',
|
||||
default => '$this->request->' . $_key . '(\'' . $val['Field'] . '\', date(\'Y-m-d H:i:s\'))',
|
||||
};
|
||||
$html .= '
|
||||
\'' . str_pad($val['Field'] . '\'', $length, ' ', STR_PAD_RIGHT) . ' => ' . str_pad($_tps . ',', 60, ' ', STR_PAD_RIGHT) . $comment;
|
||||
} else {
|
||||
$tmp = 'null';
|
||||
if (isset($number[0])) {
|
||||
if (strpos(',', $number[0])) {
|
||||
$tmp = '[' . $number[1] . ',' . $number[3] . ']';
|
||||
$_field['min'] = $number[1];
|
||||
$_field['max'] = $number[3];
|
||||
} else {
|
||||
$tmp = '[0,' . $number[1] . ']';
|
||||
$_field['min'] = 0;
|
||||
$_field['max'] = $number[1];
|
||||
}
|
||||
}
|
||||
if ($key == 'string') {
|
||||
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ', ' . $tmp . ')';
|
||||
} else if ($type == 'int') {
|
||||
if ($number[0] == 10) {
|
||||
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', time())';
|
||||
} else {
|
||||
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ')';
|
||||
}
|
||||
} else if ($type == 'float') {
|
||||
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ', ' . ($number[3] ?? '2') . ')';
|
||||
} else if ($key == 'email') {
|
||||
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ')';
|
||||
} else if ($key == 'timestamp') {
|
||||
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', time())';
|
||||
} else {
|
||||
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ')';
|
||||
}
|
||||
$html .= '
|
||||
\'' . str_pad($val['Field'] . '\'', $length, ' ', STR_PAD_RIGHT) . ' => ' . str_pad($_tps . ',', 60, ' ', STR_PAD_RIGHT) . $comment;
|
||||
}
|
||||
}
|
||||
$this->rules[$val['Field']] = $_field;
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $fields
|
||||
* @return int
|
||||
*/
|
||||
private function getMaxLength($fields): int
|
||||
{
|
||||
$length = 0;
|
||||
foreach ($fields as $key => $val) {
|
||||
if (mb_strlen($val['Field'] . ' >=') > $length) $length = mb_strlen($val['Field'] . ' >=');
|
||||
}
|
||||
return $length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fields
|
||||
* @return string
|
||||
*/
|
||||
private function getWhere($fields): string
|
||||
{
|
||||
$html = '';
|
||||
|
||||
$length = $this->getMaxLength($fields);
|
||||
foreach ($fields as $key => $val) {
|
||||
preg_match('/\d+/', $val['Type'], $number);
|
||||
|
||||
$type = strtolower(preg_replace('/\(\d+\)/', '', $val['Type']));
|
||||
|
||||
$first = preg_replace('/\s+\w+/', '', $type);
|
||||
|
||||
if ($type == 'timestamp') continue;
|
||||
if ($type == 'json') continue;
|
||||
|
||||
foreach ($this->type as $_key => $value) {
|
||||
if (!in_array(strtolower($first), $value)) continue;
|
||||
$comment = '//' . $val['Comment'];
|
||||
if ($type == 'date' || $type == 'datetime' || $type == 'time') {
|
||||
$_tps = '$this->request->query(\'' . $val['Field'] . '\', null)';
|
||||
$html .= '
|
||||
$pWhere[\'' . str_pad($val['Field'] . ' <=\']', $length, ' ', STR_PAD_RIGHT) . ' = ' . str_pad($_tps . ';', 60, ' ', STR_PAD_RIGHT) . $comment;
|
||||
$html .= '
|
||||
$pWhere[\'' . str_pad($val['Field'] . ' >=\']', $length, ' ', STR_PAD_RIGHT) . ' = ' . str_pad($_tps . ';', 60, ' ', STR_PAD_RIGHT) . $comment;
|
||||
} else {
|
||||
|
||||
$_tps = '$this->request->query(\'' . $val['Field'] . '\', null)';
|
||||
$html .= '
|
||||
$pWhere[\'' . str_pad($val['Field'] . '\']', $length, ' ', STR_PAD_RIGHT) . ' = ' . str_pad($_tps . ';', 60, ' ', STR_PAD_RIGHT) . $comment;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Gii;
|
||||
|
||||
class GiiJsonRpc extends GiiBase
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function create(): array
|
||||
{
|
||||
return [
|
||||
$this->createInterface($this->input->getArgument('name')),
|
||||
$this->createProducers($this->input->getArgument('name')),
|
||||
$this->createConsumer($this->input->getArgument('name')),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
private function createInterface($name): string
|
||||
{
|
||||
$html = '<?php
|
||||
|
||||
namespace Rpc;
|
||||
|
||||
|
||||
interface ' . ucfirst($name) . 'RpcInterface
|
||||
{
|
||||
|
||||
|
||||
}';
|
||||
|
||||
|
||||
$name = ucfirst($name) . 'RpcInterface.php';
|
||||
if (!is_dir(APP_PATH . '/rpc/')) {
|
||||
mkdir(APP_PATH . '/rpc/');
|
||||
}
|
||||
file_put_contents(APP_PATH . '/rpc/' . $name, $html);
|
||||
|
||||
return $name;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private function createProducers($name): string
|
||||
{
|
||||
$html = '<?php
|
||||
|
||||
namespace Rpc\Producers;
|
||||
|
||||
|
||||
use Kiri\Annotation\Target;
|
||||
use Kiri\Annotation\Mapping;
|
||||
use Rpc\\' . ucfirst($name) . 'RpcInterface;
|
||||
use Exception;
|
||||
use Kiri\Rpc\JsonRpcConsumers;
|
||||
|
||||
|
||||
#[Target]
|
||||
#[Mapping(' . ucfirst($name) . 'RpcInterface::class)]
|
||||
class ' . ucfirst($name) . 'RpcService extends JsonRpcConsumers implements ' . ucfirst($name) . 'RpcInterface
|
||||
{
|
||||
|
||||
protected string $name = \'' . $name . '\';
|
||||
|
||||
|
||||
|
||||
}';
|
||||
|
||||
$name = ucfirst($name) . 'RpcService.php';
|
||||
if (!is_dir(APP_PATH . '/rpc/Producers/')) {
|
||||
mkdir(APP_PATH . '/rpc/Producers/');
|
||||
}
|
||||
file_put_contents(APP_PATH . '/rpc/Producers/' . $name, $html);
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
|
||||
private function createConsumer($name): string
|
||||
{
|
||||
$html = '<?php
|
||||
|
||||
namespace Rpc\Consumers;
|
||||
|
||||
|
||||
use Kiri\Annotation\Target;
|
||||
use Kiri\Rpc\Annotation\JsonRpc;
|
||||
use Kiri\Message\Handler\Controller;
|
||||
use Rpc\\' . ucfirst($name) . 'RpcInterface;
|
||||
|
||||
|
||||
#[Target]
|
||||
#[JsonRpc(service: \'' . $name . '\', version: \'2.0\')]
|
||||
class ' . ucfirst($name) . 'RpcConsumer extends Controller implements ' . ucfirst($name) . 'RpcInterface
|
||||
{
|
||||
|
||||
|
||||
|
||||
}';
|
||||
|
||||
$name = ucfirst($name) . 'RpcConsumer.php';
|
||||
if (!is_dir(APP_PATH . '/rpc/Consumers/')) {
|
||||
mkdir(APP_PATH . '/rpc/Consumers/');
|
||||
}
|
||||
file_put_contents(APP_PATH . '/rpc/Consumers/' . $name, $html);
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user