From c337280d4e9ccb140d57132a9935dca501f2834e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mr=C2=B7x?= Date: Wed, 3 Mar 2021 18:35:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Annotation/Annotation.php | 319 ++------------------------- Annotation/Attribute.php | 26 +++ Annotation/Event.php | 2 +- Annotation/Inject.php | 19 +- Annotation/Loader.php | 184 +++++++++++++++ Annotation/Model/Get.php | 17 +- Annotation/Model/Set.php | 37 ++++ Annotation/RequestValidator.php | 2 +- Annotation/Route/After.php | 18 +- Annotation/Route/Document.php | 4 +- Annotation/Route/Filter.php | 15 +- Annotation/Route/Interceptor.php | 17 +- Annotation/Route/Limits.php | 20 +- Annotation/Route/Middleware.php | 19 +- Annotation/Route/Node.php | 45 ---- Annotation/Route/Route.php | 17 +- Annotation/Route/Socket.php | 15 +- Annotation/Target.php | 2 +- Database/Base/BaseActiveRecord.php | 77 +++++-- HttpServer/Events/OnWorkerStart.php | 1 - HttpServer/Route/Middleware.php | 8 +- HttpServer/Route/Node.php | 95 ++++---- HttpServer/Route/Router.php | 9 +- System/Abstracts/BaseApplication.php | 58 +++-- System/Application.php | 6 +- 25 files changed, 533 insertions(+), 499 deletions(-) create mode 100644 Annotation/Attribute.php create mode 100644 Annotation/Loader.php create mode 100644 Annotation/Model/Set.php delete mode 100644 Annotation/Route/Node.php diff --git a/Annotation/Annotation.php b/Annotation/Annotation.php index 6e3dfc02..32a355d8 100644 --- a/Annotation/Annotation.php +++ b/Annotation/Annotation.php @@ -4,16 +4,8 @@ namespace Annotation; -use Exception; -use JetBrains\PhpStorm\Pure; -use ReflectionAttribute; -use ReflectionClass; -use ReflectionException; -use ReflectionMethod; +use DirectoryIterator; use Snowflake\Abstracts\Component; -use Snowflake\Exception\NotFindClassException; -use Snowflake\Exception\NotFindPropertyException; -use Snowflake\Snowflake; /** * Class Annotation @@ -22,28 +14,13 @@ use Snowflake\Snowflake; class Annotation extends Component { - private array $_annotations = []; + + private Loader $_loader; - private array $_classes = []; - - - private array $_targets = []; - - - private array $_methods = []; - - - private array $_properties = []; - - - /** - * @param array $handler - * @param $name - */ - public function addMethodAttribute(array $handler, $name) + public function init(): void { - $this->_methods[get_class($handler[0])][$name] = $handler; + $this->_loader = new Loader(); } @@ -54,7 +31,16 @@ class Annotation extends Component */ public function getMethods(string $className): array { - return $this->_methods[$className] ?? []; + return $this->_loader->getMethod($className); + } + + + /** + * @param object $class + */ + public function injectProperty(object $class) + { + $this->_loader->injectProperty(get_class($class), $class); } @@ -62,281 +48,12 @@ class Annotation extends Component * @param string $path * @param string $namespace * @param string $alias - * @return $this - * @throws ReflectionException|NotFindPropertyException|NotFindClassException - */ - public function read(string $path, string $namespace, string $alias = 'root'): static - { - return $this->scanDir(glob($path . '*'), $namespace, $alias); - } - - - /** - * @param array $paths - * @param string $namespace - * @param string $alias - * @return $this - * @throws ReflectionException|NotFindPropertyException - * @throws NotFindClassException - * @throws Exception - */ - private function scanDir(array $paths, string $namespace, string $alias): static - { - foreach ($paths as $path) { - $explode = explode('/', $path); - - $explode_pop = array_pop($explode); - if (is_file($path)) { - if (!str_contains($path, '.php')) { - continue; - } - $explode_pop = str_replace('.php', '', $explode_pop); - $this->getReflect($namespace . '\\' . $explode_pop, $alias); - } else { - $this->scanDir(glob($path . '/*'), $namespace . '\\' . $explode_pop, $alias); - } - } - return $this; - } - - - /** - * @param string $class - * @param string $alias - * @return array - * @throws Exception - */ - private function getReflect(string $class, string $alias): array - { - try { - $reflect = $this->reflectClass($class); - if (empty($reflect) || !$reflect->isInstantiable()) { - return []; - } - $object = $reflect->newInstance(); - $this->resolveMethod($reflect, $class, $alias, $object); - return $this->targets($reflect); - } catch (\Throwable $throwable) { - $this->addError($throwable); - return []; - } - } - - - /** - * @param ReflectionClass $reflect - * @param $class - * @param $alias - * @param $object - * @throws NotFindPropertyException - */ - private function resolveMethod(ReflectionClass $reflect, $class, $alias, $object) - { - $targets = $reflect->getAttributes(Target::class); - if (empty($targets)) { - return; - } - foreach ($reflect->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { - if ($method->class != $class) { - continue; - } - $this->resolveAnnotations($method, $alias, $object); - } - $this->resolveProperty($reflect, $object); - } - - - /** - * @param ReflectionClass $reflectionClass - * @param $object - * @throws NotFindPropertyException - */ - private function resolveProperty(ReflectionClass $reflectionClass, $object) - { - $property = $reflectionClass->getProperties(); - if (!isset($this->_properties[get_class($object)])) { - $this->_properties[get_class($object)] = []; - } - foreach ($property as $value) { - if ($value->isStatic()) continue; - $attributes = $value->getAttributes(); - if (count($attributes) < 1) { - continue; - } - foreach ($attributes as $attribute) { - /** @var IAnnotation $annotation */ - $annotation = $this->instance($attribute); - if (empty($annotation)) { - continue; - } - $annotation = $annotation->execute([$object, $value->getName()]); - $this->_properties[get_class($object)][$value->getName()] = $annotation; - - if ($value->isPublic()) { - continue; - } - if (!method_exists($object, ($name = 'set' . ucfirst($value->getName())))) { - throw new NotFindPropertyException('set property need method ' . $name); - } - } - } - } - - - /** - * @param $class - * @param string $property - * @return mixed|null - */ - public function getProperty($class, $property = ''): ?array - { - if (is_object($class)) { - $class = get_class($class); - } - if (!isset($this->_properties[$class])) { - return null; - } - - if (!empty($property)) { - return $this->_properties[$class][$property] ?? null; - } - - return $this->_properties[$class]; - } - - - /** - * @param $class * @return void */ - public function setProperty($class): void + public function read(string $path, string $namespace, string $alias = 'root'): void { - $lists = $this->getProperty($class); - if (empty($lists)) { - return; - } - Snowflake::configure($class, $lists); + + $this->_loader->_scanDir(new DirectoryIterator($path), $namespace); } - - /** - * @param string $class - * @return ReflectionClass|null - * @throws ReflectionException|NotFindClassException - */ - private function reflectClass(string $class): ?ReflectionClass - { - return Snowflake::getDi()->getReflect($class); - } - - - /** - * @param ReflectionMethod $method - * @param $alias - * @param $object - * @return array - */ - private function resolveAnnotations(ReflectionMethod $method, $alias, $object): array - { - $attributes = $method->getAttributes(); - if (count($attributes) < 1) { - return []; - } - - $name = get_class($object) . '_' . $method->getName(); - if (!isset($this->_annotations[$name])) { - $this->_annotations[$name] = []; - } - - foreach ($attributes as $attribute) { - /** @var IAnnotation $class */ - $class = $this->instance($attribute); - if ($class === null) { - continue; - } - $this->_annotations[$name][] = $class->execute([$object, $method->getName()]); - } - return []; - } - - - /** - * @param $class - * @param $method - * @return mixed - */ - #[Pure] public function getAnnotationByMethod($class, $method): array - { - if (is_object($class)) { - $class = get_class($class); - } - if (!isset($this->_annotations[$class . '_' . $method])) { - return []; - } - return $this->_annotations[$class . '_' . $method]; - } - - - /** - * @param $className - * @param string $method - * @return array - */ - public function getByClass($className, $method = ''): array - { - if (!isset($this->_classes[$className])) { - return []; - } - if (empty($method)) { - return $this->_classes[$className]; - } - foreach ($this->_classes[$className] as $_method => $class) { - if ($method == $_method) { - return [$class]; - } - } - return []; - } - - - /** - * @param ReflectionClass $reflect - * @return array - */ - private function targets(ReflectionClass $reflect): array - { - $name = $reflect->getName(); - if (!isset($this->_classes[$name])) { - $this->_classes[$name] = []; - } - $attributes = $reflect->getAttributes(); - if (count($attributes) > 0) { - if (!isset($this->_targets[$name])) { - $this->_targets[$name] = []; - } - foreach ($attributes as $attribute) { - $class = $this->instance($attribute); - if ($class === null) { - continue; - } - $this->_targets[$name][] = $class; - } - } - return []; - } - - - /** - * @param ReflectionAttribute $attribute - * @return array|object|null - */ - private function instance(ReflectionAttribute $attribute): array|object|null - { - if (!class_exists($attribute->getName())) { - return null; - } - return $attribute->newInstance(); - } - - } diff --git a/Annotation/Attribute.php b/Annotation/Attribute.php new file mode 100644 index 00000000..6bc79df0 --- /dev/null +++ b/Annotation/Attribute.php @@ -0,0 +1,26 @@ +has($this->className)) { - return Snowflake::app()->get($this->className); + [$object, $property] = $handler; + if (class_exists($this->className)) { + return $object->$property = Snowflake::createObject($this->className, $this->args); } - return Snowflake::createObject($this->className, $this->args); + + $application = Snowflake::app(); + if (!$application->has($this->className)) { + return $object; + } + + $object->$property = $application->get($this->className); + if (!empty($this->args) && is_object($object->$property)) { + Snowflake::configure($object->$property, $this->args); + } + return $object; } } diff --git a/Annotation/Loader.php b/Annotation/Loader.php new file mode 100644 index 00000000..8d70f3d0 --- /dev/null +++ b/Annotation/Loader.php @@ -0,0 +1,184 @@ +_scanDir(new DirectoryIterator($path), $namespace); + } + + + /** + * @return array + */ + public function getClasses(): array + { + return $this->_classes; + } + + + /** + * @param string $class + * @param string $property + * @return mixed + */ + public function getProperty(string $class, string $property = ''): mixed + { + if (!isset($this->_classes[$class])) { + return null; + } + $properties = $this->_classes[$class]['property']; + if (!empty($property) && isset($properties[$property])) { + return $properties[$property]; + } + return $properties; + } + + + /** + * @param string $class + * @param mixed $handler + * @return Loader + */ + public function injectProperty(string $class, object $handler): static + { + $properties = $this->getProperty($class); + if (empty($properties)) { + return $this; + } + foreach ($properties as $property => $attributes) { + foreach ($attributes as $attribute) { + $attribute->execute([$handler, $property]); + } + } + return $this; + } + + + /** + * @param string $class + * @param string $method + * @return mixed + */ + public function getMethod(string $class, string $method = ''): mixed + { + if (!isset($this->_classes[$class])) { + return null; + } + $properties = $this->_classes[$class]['methods']; + if (!empty($property) && isset($properties[$method])) { + return $properties[$method]; + } + return $properties; + } + + + /** + * @param string $class + * @return array + */ + public function getTarget(string $class): array + { + return $this->_classes[$class] ?? []; + } + + + /** + * @param DirectoryIterator $paths + * @param $namespace + */ + public function _scanDir(DirectoryIterator $paths, $namespace) + { + foreach ($paths as $path) { + if ($path->getFilename() === '.' || $path->getFilename() === '..') { + continue; + } + if (str_starts_with($path->getFilename(), '.')) { + continue; + } + if ($path->isDir()) { + $this->_scanDir(new DirectoryIterator($path->getRealPath()), $namespace); + continue; + } + if ($path->getExtension() !== 'php') { + continue; + } + + $replace = str_replace(__DIR__ . '/', '', $path->getPathname()); + + $replace = str_replace('.php', '', $replace); + $replace = str_replace(DIRECTORY_SEPARATOR, '\\', $replace); + $explode = explode('\\', $replace); + array_shift($explode); + + try { + $replace = new ReflectionClass($namespace . implode('\\', $explode)); + if (!$replace->isInstantiable()) { + continue; + } + + $_array = ['target' => [], 'methods' => [], 'property' => []]; + foreach ($replace->getAttributes() as $attribute) { + if ($attribute->getName() == Attribute::class) { + continue; + } + $_array['target'][] = $attribute->newInstance(); + } + + $methods = $replace->getMethods(ReflectionMethod::IS_PUBLIC); + foreach ($methods as $method) { + $_method = []; + foreach ($method->getAttributes() as $attribute) { + if (!class_exists($attribute->getName())) { + continue; + } + $_method[] = $attribute->newInstance(); + } + $_array['methods'][$method->getName()] = $_method; + } + + $methods = $replace->getProperties(ReflectionMethod::IS_PUBLIC ^ ReflectionProperty::IS_STATIC); + foreach ($methods as $method) { + $_property = []; + foreach ($method->getAttributes() as $attribute) { + if (!class_exists($attribute->getName())) { + continue; + } + $_property[] = $attribute->newInstance(); + } + $_array['property'][$method->getName()] = $_property; + } + + $this->_classes[$replace->getName()] = $_array; + } catch (Throwable $throwable) { + echo $throwable->getMessage() . PHP_EOL; + } + } + } +} diff --git a/Annotation/Model/Get.php b/Annotation/Model/Get.php index ee884314..05be24c7 100644 --- a/Annotation/Model/Get.php +++ b/Annotation/Model/Get.php @@ -5,18 +5,15 @@ namespace Annotation\Model; use Annotation\Annotation; -use Annotation\IAnnotation; use Attribute; use Database\ActiveRecord; -use Snowflake\Exception\ComponentException; -use Snowflake\Snowflake; /** * Class Get * @package Annotation\Model */ -#[Attribute(Attribute::TARGET_METHOD)] class Get implements IAnnotation +#[Attribute(Attribute::TARGET_METHOD)] class Get extends \Annotation\Attribute { @@ -33,16 +30,14 @@ use Snowflake\Snowflake; /** * @param array $handler - * @return Annotation - * @throws ComponentException + * @return ActiveRecord */ - public function execute(array $handler): Annotation + public function execute(array $handler): ActiveRecord { - // TODO: Implement execute() method. - $annotation = Snowflake::app()->getAttributes(); - $annotation->addMethodAttribute($handler, $this->name); + /** @var ActiveRecord $activeRecord */ + [$activeRecord, $method] = $handler; - return $annotation; + return $activeRecord->addGets($this->name, $method); } diff --git a/Annotation/Model/Set.php b/Annotation/Model/Set.php new file mode 100644 index 00000000..ee82c42c --- /dev/null +++ b/Annotation/Model/Set.php @@ -0,0 +1,37 @@ +addSets($this->name, $method); + } + + +} diff --git a/Annotation/RequestValidator.php b/Annotation/RequestValidator.php index 2db460fb..435dc924 100644 --- a/Annotation/RequestValidator.php +++ b/Annotation/RequestValidator.php @@ -11,7 +11,7 @@ use validator\Validator; * Class RequestValidator * @package Annotation */ -#[\Attribute(\Attribute::TARGET_METHOD)] class RequestValidator implements IAnnotation +#[\Attribute(\Attribute::TARGET_METHOD)] class RequestValidator extends Attribute { /** diff --git a/Annotation/Route/After.php b/Annotation/Route/After.php index 81fe06c7..feec0f99 100644 --- a/Annotation/Route/After.php +++ b/Annotation/Route/After.php @@ -4,31 +4,33 @@ namespace Annotation\Route; -use Annotation\IAnnotation; -use JetBrains\PhpStorm\Pure; -use ReflectionException; -use Snowflake\Exception\NotFindClassException; +use Annotation\Attribute; use Snowflake\Snowflake; /** * Class Interceptor * @package Annotation\Route */ -#[\Attribute(\Attribute::TARGET_METHOD)] class After implements IAnnotation +#[\Attribute(\Attribute::TARGET_METHOD)] class After extends Attribute { - use Node; - /** * Interceptor constructor. * @param \HttpServer\IInterface\After|\HttpServer\IInterface\After[] $after * @throws */ - #[Pure] public function __construct(public string|array $after) + public function __construct(public string|array $after) { if (is_string($this->after)) { $this->after = [$this->after]; } + foreach ($this->after as $key => $value) { + $sn = Snowflake::createObject($value); + if (!($sn instanceof \HttpServer\IInterface\After)) { + continue; + } + $this->after[$key] = [$sn, 'onHandler']; + } } diff --git a/Annotation/Route/Document.php b/Annotation/Route/Document.php index a63aad90..760406aa 100644 --- a/Annotation/Route/Document.php +++ b/Annotation/Route/Document.php @@ -4,13 +4,13 @@ namespace Annotation\Route; -use Annotation\IAnnotation; +use Annotation\Attribute; /** * Class Document * @package Annotation\Route */ -#[\Attribute(\Attribute::TARGET_METHOD)] class Document implements IAnnotation +#[\Attribute(\Attribute::TARGET_METHOD)] class Document extends Attribute { const INTEGER = 'int'; diff --git a/Annotation/Route/Filter.php b/Annotation/Route/Filter.php index d493c530..4fa9e1b7 100644 --- a/Annotation/Route/Filter.php +++ b/Annotation/Route/Filter.php @@ -4,11 +4,13 @@ namespace Annotation\Route; +use Annotation\Attribute; + /** * Class Filter * @package Annotation\Route */ -#[\Attribute(\Attribute::TARGET_METHOD)] class Filter +#[\Attribute(\Attribute::TARGET_METHOD)] class Filter extends Attribute { /** @@ -20,4 +22,15 @@ namespace Annotation\Route; } + /** + * @param array $handler + * @return array + */ + public function execute(array $handler): array + { + // TODO: Implement execute() method. + return $handler; + } + + } diff --git a/Annotation/Route/Interceptor.php b/Annotation/Route/Interceptor.php index 21b84b89..28ec3c84 100644 --- a/Annotation/Route/Interceptor.php +++ b/Annotation/Route/Interceptor.php @@ -4,20 +4,17 @@ namespace Annotation\Route; -use Annotation\IAnnotation; +use Annotation\Attribute; use JetBrains\PhpStorm\Pure; -use ReflectionException; -use Snowflake\Exception\NotFindClassException; use Snowflake\Snowflake; /** * Class Interceptor * @package Annotation\Route */ -#[\Attribute(\Attribute::TARGET_METHOD)] class Interceptor implements IAnnotation +#[\Attribute(\Attribute::TARGET_METHOD)] class Interceptor extends Attribute { - use Node; /** * Interceptor constructor. @@ -29,6 +26,16 @@ use Snowflake\Snowflake; if (is_string($this->interceptor)) { $this->interceptor = [$this->interceptor]; } + + foreach ($this->interceptor as $key => $value) { + $sn = Snowflake::createObject($value); + + if (!($sn instanceof \HttpServer\IInterface\Interceptor)) { + continue; + } + + $this->interceptor[$key] = [$sn, 'Interceptor']; + } } diff --git a/Annotation/Route/Limits.php b/Annotation/Route/Limits.php index 47b04845..1928916c 100644 --- a/Annotation/Route/Limits.php +++ b/Annotation/Route/Limits.php @@ -4,31 +4,37 @@ namespace Annotation\Route; -use Annotation\IAnnotation; -use JetBrains\PhpStorm\Pure; -use ReflectionException; -use Snowflake\Exception\NotFindClassException; +use Annotation\Attribute; use Snowflake\Snowflake; /** * Class Limits * @package Annotation\Route */ -#[\Attribute(\Attribute::TARGET_METHOD)] class Limits implements IAnnotation +#[\Attribute(\Attribute::TARGET_METHOD)] class Limits extends Attribute { - use Node; /** * Limits constructor. * @param string|array $limits * @throws */ - #[Pure] public function __construct(public string|array $limits) + public function __construct(public string|array $limits) { if (is_string($this->limits)) { $this->limits = [$this->limits]; } + + foreach ($this->limits as $key => $value) { + $sn = Snowflake::createObject($value); + + if (!($sn instanceof \HttpServer\IInterface\Limits)) { + continue; + } + + $this->limits[$key] = [$sn, 'next']; + } } diff --git a/Annotation/Route/Middleware.php b/Annotation/Route/Middleware.php index e0d24731..15412b25 100644 --- a/Annotation/Route/Middleware.php +++ b/Annotation/Route/Middleware.php @@ -4,32 +4,35 @@ namespace Annotation\Route; -use Annotation\IAnnotation; -use JetBrains\PhpStorm\Pure; -use ReflectionException; -use Snowflake\Exception\NotFindClassException; +use Annotation\Attribute; use Snowflake\Snowflake; /** * Class Middleware * @package Annotation\Route */ -#[\Attribute(\Attribute::TARGET_METHOD)] class Middleware implements IAnnotation +#[\Attribute(\Attribute::TARGET_METHOD)] class Middleware extends Attribute { - use Node; - /** * Interceptor constructor. * @param string|array $middleware * @throws */ - #[Pure] public function __construct(public string|array $middleware) + public function __construct(public string|array $middleware) { if (is_string($this->middleware)) { $this->middleware = [$this->middleware]; } + foreach ($this->middleware as $key => $value) { + $sn = Snowflake::createObject($value); + + if (!($sn instanceof \HttpServer\IInterface\Middleware)) { + continue; + } + $this->middleware[$key] = [$sn, 'onHandler']; + } } diff --git a/Annotation/Route/Node.php b/Annotation/Route/Node.php deleted file mode 100644 index c661e526..00000000 --- a/Annotation/Route/Node.php +++ /dev/null @@ -1,45 +0,0 @@ -get($class); - if ($object instanceof Interceptor) { - $array[] = [$object, 'Interceptor']; - } - if ($object instanceof Limits) { - $array[] = [$object, 'next']; - } - if ($object instanceof After) { - $array[] = [$object, 'onHandler']; - } - if ($object instanceof Middleware) { - $array[] = [$object, 'onHandler']; - } - } - return $array; - } - -} diff --git a/Annotation/Route/Route.php b/Annotation/Route/Route.php index 211211cd..257bb12c 100644 --- a/Annotation/Route/Route.php +++ b/Annotation/Route/Route.php @@ -4,26 +4,27 @@ namespace Annotation\Route; -use Closure; -use Exception; -use HttpServer\Route\Node; +use Annotation\Attribute; use HttpServer\Route\Router; +use ReflectionException; use Snowflake\Exception\ComponentException; use Snowflake\Exception\ConfigException; +use Snowflake\Exception\NotFindClassException; use Snowflake\Snowflake; -use Annotation\IAnnotation; -#[\Attribute(\Attribute::TARGET_METHOD)] class Route implements IAnnotation +#[\Attribute(\Attribute::TARGET_METHOD)] 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 $method, + public string $version = 'v.1.0' ) { } @@ -34,13 +35,15 @@ use Annotation\IAnnotation; * @return Router * @throws ComponentException * @throws ConfigException + * @throws ReflectionException + * @throws NotFindClassException */ public function execute(array $handler): Router { // TODO: Implement setHandler() method. $router = Snowflake::app()->getRouter(); - $router->addRoute($this->uri, $handler, $this->method); + $router->addRoute($this->uri . $this->version, $handler, $this->method); return $router; } diff --git a/Annotation/Route/Socket.php b/Annotation/Route/Socket.php index 2d1f06d0..e24f7a35 100644 --- a/Annotation/Route/Socket.php +++ b/Annotation/Route/Socket.php @@ -4,10 +4,7 @@ namespace Annotation\Route; -use Annotation\IAnnotation; -use Closure; -use Exception; -use HttpServer\Route\Node; +use Annotation\Attribute; use HttpServer\Route\Router; use ReflectionException; use Snowflake\Exception\ComponentException; @@ -19,7 +16,7 @@ use Snowflake\Snowflake; * Class Socket * @package Annotation */ -#[\Attribute(\Attribute::TARGET_METHOD)] class Socket implements IAnnotation +#[\Attribute(\Attribute::TARGET_METHOD)] class Socket extends Attribute { const CLOSE = 'CLOSE'; @@ -30,10 +27,12 @@ use Snowflake\Snowflake; * Socket constructor. * @param string $event * @param string|null $uri + * @param string $version */ public function __construct( public string $event, - public ?string $uri = null + public ?string $uri = null, + public string $version = 'v.1.0' ) { } @@ -44,6 +43,8 @@ use Snowflake\Snowflake; * @return Router * @throws ComponentException * @throws ConfigException + * @throws ReflectionException + * @throws NotFindClassException */ public function execute(array $handler): Router { @@ -52,7 +53,7 @@ use Snowflake\Snowflake; $method = $this->event . '::' . (is_null($this->uri) ? 'event' : $this->uri); - $router->addRoute($method, $handler, 'sw::socket'); + $router->addRoute($method . $this->version, $handler, 'sw::socket'); return $router; } diff --git a/Annotation/Target.php b/Annotation/Target.php index fa8a0a4c..045e3dd7 100644 --- a/Annotation/Target.php +++ b/Annotation/Target.php @@ -8,7 +8,7 @@ namespace Annotation; * Class Target * @package Annotation */ -#[\Attribute(\Attribute::TARGET_CLASS)] class Target +#[\Attribute(\Attribute::TARGET_CLASS)] class Target extends Attribute { } diff --git a/Database/Base/BaseActiveRecord.php b/Database/Base/BaseActiveRecord.php index a48de901..df5086a2 100644 --- a/Database/Base/BaseActiveRecord.php +++ b/Database/Base/BaseActiveRecord.php @@ -11,11 +11,13 @@ namespace Database\Base; use Annotation\Event; +use Annotation\IAnnotation; use Annotation\Inject; +use Annotation\Model\Get; +use Annotation\Model\Set; use ArrayAccess; use Database\SqlBuilder; use HttpServer\Http\Context; -use JetBrains\PhpStorm\Pure; use ReflectionException; use Snowflake\Abstracts\Component; use Database\ActiveQuery; @@ -106,6 +108,7 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess */ public function init() { + $this->_annotations = []; if (!Context::hasContext(Relation::class)) { $relation = Snowflake::createObject(Relation::class); $this->_relation = Context::setContext(Relation::class, $relation); @@ -118,14 +121,53 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess /** * @throws ComponentException + * @throws NotFindClassException + * @throws ReflectionException */ private function createAnnotation() { $annotation = Snowflake::app()->getAttributes(); + $annotation->injectProperty($this); - $this->_annotations = $annotation->getMethods(get_called_class()); + $methods = $annotation->getMethods(get_called_class()); + foreach ($methods as $method => $attributes) { + foreach ($attributes as $attribute) { + if (!($attribute instanceof Get) && !($attribute instanceof Set)) { + continue; + } + $attribute->execute([$this, $method]); + } + } + } - $annotation->setProperty($this); + + /** + * @param $name + * @param $method + * @return static + */ + public function addGets($name, $method): static + { + if (!isset($this->_annotations['get'])) { + $this->_annotations['get'] = []; + } + $this->_annotations['get'][$name] = [$this, $method]; + return $this; + } + + + /** + * @param $name + * @param $method + * @return static + */ + public function addSets($name, $method): static + { + if (!isset($this->_annotations['set'])) { + $this->_annotations['set'] = []; + } + $this->_annotations['set'][$name] = [$this, $method]; + return $this; } @@ -157,9 +199,10 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess /** * @return mixed - * - * get last exception or other error * @throws ComponentException + * @throws NotFindClassException + * @throws ReflectionException + * get last exception or other error */ public function getLastError(): mixed { @@ -745,15 +788,16 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess { if (!$this->has($name)) { parent::__set($name, $value); + return; + } + if ($this->hasAnnotation($name, 'set')) { + call_user_func($this->_annotations['set'][$name], $value); } else { - $sets = 'set' . ucfirst($name) . 'Attribute'; - if (method_exists($this, $sets)) { - $value = $this->$sets($value); - } $this->_attributes[$name] = $value; } } + /** * @param $name * @return mixed @@ -763,16 +807,13 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess { $value = $this->_attributes[$name] ?? null; if ($this->hasAnnotation($name)) { - return call_user_func($this->_annotations[$name], $value); + return call_user_func($this->_annotations['get'][$name], $value); } if (array_key_exists($name, $this->_attributes)) { return static::getColumns()->_decode($name, $value); } if (isset($this->_relate[$name])) { - $gets = $this->{$this->_relate[$name]}(); - } - if (isset($gets)) { - return $this->resolveClass($gets); + return $this->resolveClass($this->{$this->_relate[$name]}()); } return parent::__get($name); } @@ -789,11 +830,15 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess /** * @param $name + * @param string $type * @return bool */ - protected function hasAnnotation($name): bool + protected function hasAnnotation($name, $type = 'get'): bool { - return isset($this->_annotations[$name]); + if (!isset($this->_annotations[$type])) { + return false; + } + return isset($this->_annotations[$type][$name]); } diff --git a/HttpServer/Events/OnWorkerStart.php b/HttpServer/Events/OnWorkerStart.php index ccecf179..f70a31b3 100644 --- a/HttpServer/Events/OnWorkerStart.php +++ b/HttpServer/Events/OnWorkerStart.php @@ -19,7 +19,6 @@ use Swoole\Timer; * Class OnWorkerStart * @package HttpServer\Events */ -#[Target] class OnWorkerStart extends Callback { diff --git a/HttpServer/Route/Middleware.php b/HttpServer/Route/Middleware.php index 7e7234a5..4bb1e150 100644 --- a/HttpServer/Route/Middleware.php +++ b/HttpServer/Route/Middleware.php @@ -78,16 +78,16 @@ class Middleware } foreach ($annotation as $attribute) { if ($attribute instanceof Interceptor) { - $node->addInterceptor($attribute->reflectClass($attribute->interceptor)); + $node->addInterceptor($attribute->interceptor); } if ($attribute instanceof After) { - $node->addAfter($attribute->reflectClass($attribute->after)); + $node->addAfter($attribute->after); } if ($attribute instanceof RMiddleware) { - $node->addMiddleware($attribute->reflectClass($attribute->middleware)); + $node->addMiddleware($attribute->middleware); } if ($attribute instanceof Limits) { - $node->addLimits($attribute->reflectClass($attribute->limits)); + $node->addLimits($attribute->limits); } } } diff --git a/HttpServer/Route/Node.php b/HttpServer/Route/Node.php index f0144303..ba20ae0f 100644 --- a/HttpServer/Route/Node.php +++ b/HttpServer/Route/Node.php @@ -10,6 +10,9 @@ use HttpServer\Abstracts\HttpService; use HttpServer\Http\Request; use Exception; +use HttpServer\IInterface\After; +use HttpServer\IInterface\Interceptor; +use HttpServer\IInterface\Limits; use JetBrains\PhpStorm\Pure; use ReflectionException; use Snowflake\Core\Json; @@ -379,35 +382,20 @@ class Node extends HttpService } - /** - * @param $middles - * @throws - */ - public function bindMiddleware(array $middles) - { - $_tmp = []; - if (empty($middles)) { - return; - } - $this->middleware = $this->each($middles, $_tmp); - } - - /** * @param array|Closure|string $class + * @return Node * @throws ReflectionException * @throws NotFindClassException * @throws Exception */ - public function addMiddleware(Closure|string|array $class) + public function addMiddleware(Closure|string|array $class): static { - if (empty($class)) return; if (is_string($class)) { - $class = Snowflake::createObject($class); - if (!($class instanceof \HttpServer\IInterface\Middleware)) { - return; + $class = $this->resolve_aop($class); + if ($class === null) { + return $this; } - $class = [[$class, 'onHandler']]; } if (!is_array($class) || is_object($class[0])) { $class = [$class]; @@ -418,6 +406,30 @@ class Node extends HttpService } $this->middleware[] = $closure; } + return $this; + } + + + /** + * @param string $class + * @return array|null + * @throws NotFindClassException + * @throws ReflectionException + */ + private function resolve_aop(string $class): array|null + { + $class = Snowflake::createObject($class); + if ($class instanceof \HttpServer\IInterface\Middleware) { + return [$class, 'onHandler']; + } else if ($class instanceof Interceptor) { + return [$class, 'Interceptor']; + } else if ($class instanceof After) { + return [$class, 'onHandler']; + } else if ($class instanceof Limits) { + return [$class, 'next']; + } else { + return null; + } } @@ -451,13 +463,22 @@ class Node extends HttpService */ public function dispatch(): mixed { - if (empty($this->callback)) { - $this->restructure(); - if (empty($this->callback)) { - return Json::to(404, $node->_error ?? 'Page not found.'); - } + if (!empty($this->callback)) { + return $this->runWith(...func_get_args()); } + if (empty($this->restructure()->callback)) { + return Json::to(404, $this->errorMsg()); + } + return $this->runWith(...func_get_args()); + } + + /** + * @return mixed + * @throws Exception + */ + private function runWith(): mixed + { $requestParams = func_get_args(); if (func_num_args() > 0) { return call_user_func($this->callback, ...$requestParams); @@ -468,27 +489,11 @@ class Node extends HttpService /** - * @param $array - * @param $_temp - * @return array - * @throws Exception + * @return string */ - private function each($array, $_temp): array + private function errorMsg(): string { - if (!is_array($array)) { - return $_temp; - } - foreach ($array as $class) { - if (is_array($class)) { - $_temp = $this->each($class, $_temp); - continue; - } - - if (!class_exists($class)) { - continue; - } - $_temp[] = Snowflake::createObject($class); - } - return $_temp; + return $this->_error ?? 'Page not found.'; } + } diff --git a/HttpServer/Route/Router.php b/HttpServer/Route/Router.php index a414f572..47a618d8 100644 --- a/HttpServer/Route/Router.php +++ b/HttpServer/Route/Router.php @@ -9,6 +9,7 @@ use HttpServer\Abstracts\HttpService; use HttpServer\Http\Request; use HttpServer\IInterface\RouterInterface; +use JetBrains\PhpStorm\Pure; use Snowflake\Abstracts\Config; use Snowflake\Exception\ComponentException; use Snowflake\Exception\ConfigException; @@ -28,6 +29,8 @@ class Router extends HttpService implements RouterInterface public array $groupTacks = []; public ?string $dir = 'App\\Http\\Controllers'; + public array $hashMap = []; + const NOT_FOUND = 'Page not found or method not allowed.'; /** @var string[] */ @@ -109,7 +112,7 @@ class Router extends HttpService implements RouterInterface * @param $path * @return string */ - private function resolve($path): string + #[Pure] private function resolve($path): string { $paths = array_column($this->groupTacks, 'prefix'); if (empty($paths)) { @@ -287,7 +290,9 @@ class Router extends HttpService implements RouterInterface if ($this->middleware instanceof \Closure) { $node->addMiddleware($this->middleware); } - $node->bindMiddleware($name); + + + $node->addMiddleware($name); return $node; } diff --git a/System/Abstracts/BaseApplication.php b/System/Abstracts/BaseApplication.php index 3c99060b..01ce4079 100644 --- a/System/Abstracts/BaseApplication.php +++ b/System/Abstracts/BaseApplication.php @@ -24,6 +24,7 @@ use HttpServer\Service\Websocket; use JetBrains\PhpStorm\Pure; use Kafka\Producer; use Annotation\Annotation as SAnnotation; +use ReflectionException; use Snowflake\Async; use Snowflake\Cache\Redis; use Snowflake\Di\Service; @@ -31,6 +32,7 @@ use Snowflake\Error\ErrorHandler; use Snowflake\Error\Logger; use Snowflake\Exception\ComponentException; use Snowflake\Exception\InitException; +use Snowflake\Exception\NotFindClassException; use Snowflake\Jwt\Jwt; use Snowflake\Pool\Connection; use Snowflake\Pool\ObjectPool; @@ -195,7 +197,8 @@ abstract class BaseApplication extends Service /** * @param $name * @return mixed - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function clone($name): mixed { @@ -230,7 +233,8 @@ abstract class BaseApplication extends Service /** * @return Logger - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getLogger(): Logger { @@ -240,7 +244,8 @@ abstract class BaseApplication extends Service /** * @return Producer - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getKafka(): Producer { @@ -250,7 +255,8 @@ abstract class BaseApplication extends Service /** * @return \Redis|Redis - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getRedis(): Redis|\Redis { @@ -269,7 +275,8 @@ abstract class BaseApplication extends Service /** * @return ErrorHandler - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getError(): ErrorHandler { @@ -279,7 +286,8 @@ abstract class BaseApplication extends Service /** * @return Connection - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getConnections(): Connection { @@ -289,7 +297,8 @@ abstract class BaseApplication extends Service /** * @return SPool - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getPool(): SPool { @@ -298,7 +307,8 @@ abstract class BaseApplication extends Service /** * @return Response - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getResponse(): Response { @@ -307,7 +317,8 @@ abstract class BaseApplication extends Service /** * @return Request - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getRequest(): Request { @@ -318,7 +329,8 @@ abstract class BaseApplication extends Service /** * @param $name * @return Table - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getTable($name): Table { @@ -328,7 +340,8 @@ abstract class BaseApplication extends Service /** * @return Config - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getConfig(): Config { @@ -338,7 +351,8 @@ abstract class BaseApplication extends Service /** * @return Router - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getRouter(): Router { @@ -348,7 +362,8 @@ abstract class BaseApplication extends Service /** * @return Event - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getEvent(): Event { @@ -358,7 +373,8 @@ abstract class BaseApplication extends Service /** * @return Jwt - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getJwt(): Jwt { @@ -368,7 +384,8 @@ abstract class BaseApplication extends Service /** * @return Server - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getServer(): Server { @@ -378,7 +395,8 @@ abstract class BaseApplication extends Service /** * @return Http|Packet|Receive|Websocket|null - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getSwoole(): Packet|Websocket|Receive|Http|null { @@ -389,6 +407,8 @@ abstract class BaseApplication extends Service /** * @return SAnnotation * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException */ public function getAttributes(): SAnnotation { @@ -398,7 +418,8 @@ abstract class BaseApplication extends Service /** * @return Async - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getAsync(): Async { @@ -408,7 +429,8 @@ abstract class BaseApplication extends Service /** * @return ObjectPool - * @throws ComponentException + * @throws ReflectionException + * @throws NotFindClassException|ComponentException */ public function getObject(): ObjectPool { diff --git a/System/Application.php b/System/Application.php index 4ccc5f3b..098b274d 100644 --- a/System/Application.php +++ b/System/Application.php @@ -108,10 +108,8 @@ class Application extends BaseApplication public function start(Input $argv): void { try { - ini_set('opcache.enable', '1'); - ini_set('opcache.enable_cli', '1'); - ini_set('opcache.jit_buffer_size', '100M'); - ini_set('opcache.jit', '1255'); + $annotation = $this->getAttributes(); + $annotation->read(APP_PATH, 'App\\'); fire(Event::SERVER_BEFORE_START);