diff --git a/.phpunit.result.cache b/.phpunit.result.cache
new file mode 100644
index 0000000..37c9cba
--- /dev/null
+++ b/.phpunit.result.cache
@@ -0,0 +1 @@
+{"version":1,"defects":{"Rudra\\Router\\Tests\\RouterAnnotationTraitTest::testAnnotation":8,"Rudra\\Router\\Tests\\RouterAnnotationTraitTest::testAnnotationCollector":8,"Rudra\\Router\\Tests\\RouterAnnotationTraitTest::testAnnotationCollectorMultilevel":8},"times":{"Rudra\\Router\\Tests\\RouterAnnotationTraitTest::testAnnotation":0.003,"Rudra\\Router\\Tests\\RouterAnnotationTraitTest::testAnnotationCollector":0.001,"Rudra\\Router\\Tests\\RouterAnnotationTraitTest::testAnnotationCollectorMultilevel":0}}
\ No newline at end of file
diff --git a/phpunit.xml b/phpunit.xml
index a16a2bb..9e72d72 100755
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -21,4 +21,8 @@
./src
+
+
+
+
diff --git a/src/MiddlewareInterface.php b/src/MiddlewareInterface.php
index ac0bbb8..2ac95b2 100755
--- a/src/MiddlewareInterface.php
+++ b/src/MiddlewareInterface.php
@@ -3,8 +3,8 @@
declare(strict_types=1);
/**
- * @author : Jagepard
- * @license https://mit-license.org/ MIT
+ * @author : Jagepard
+ * @license https://mit-license.org/ MIT
*/
namespace Rudra\Router;
diff --git a/src/Router.php b/src/Router.php
index b956bef..70e223b 100755
--- a/src/Router.php
+++ b/src/Router.php
@@ -3,8 +3,8 @@
declare(strict_types=1);
/**
- * @author : Jagepard
- * @license https://mit-license.org/ MIT
+ * @author : Jagepard
+ * @license https://mit-license.org/ MIT
*/
namespace Rudra\Router;
@@ -21,121 +21,69 @@ class Router implements RouterInterface
use RouterRequestMethodTrait;
/**
- * @param array $route
- * @throws RouterException
- * @throws ReflectionException
+ * @param array $route
+ * @return void
*/
public function set(array $route): void
{
- if (str_contains($route['method'], '|')) {
- $httpMethods = explode('|', $route['method']);
+ $httpMethods = str_contains($route['method'], '|')
+ ? explode('|', $route['method'])
+ : [$route['method']];
- foreach ($httpMethods as $httpMethod) {
- $route['method'] = $httpMethod;
- $this->handleRequestUri($route);
- }
+ foreach ($httpMethods as $httpMethod) {
+ $route['method'] = $httpMethod;
+ $this->handleRequestUri($route);
}
-
- $this->handleRequestUri($route);
}
/**
- * @param array $route
- * @param null $params
- * @throws RouterException|ReflectionException
+ * @param array $route
+ * @return void
*/
- public function directCall(array $route, $params = null): void
+ protected function handleRequestUri(array $route): void
{
- $controller = $this->rudra->get($route['controller']);
- $action = $route['action'];
+ $this->handleRequestMethod();
- if (!method_exists($controller, $action)) {
- throw new RouterException("503");
- }
+ $request = $this->rudra->request();
+ $server = $request->server();
- $controller->shipInit();
- $controller->containerInit();
- $controller->init();
- $controller->before();
- !isset($route['middleware']["before"]) ?: $this->handleMiddleware($route['middleware']["before"]);
- $this->callAction($params, $action, $controller);
- !isset($route['middleware']["after"]) ?: $this->handleMiddleware($route['middleware']["after"]);
- $controller->after();
-
- if ($this->rudra->config()->get("environment") !== "test") {
- exit();
+ // Проверяем соответствие HTTP-метода
+ if ($route['method'] !== $server->get('REQUEST_METHOD')) {
+ return;
}
- }
- protected function handleRequestMethod(): void
- {
- $requestMethod = $this->rudra->request()->server()->get("REQUEST_METHOD");
+ $uriRaw = $server->get('REQUEST_URI');
+ $parsed = parse_url($uriRaw);
+ $requestPath = $parsed && isset($parsed['path']) ? ltrim($parsed['path'], '/') : '';
+ $uriSegments = explode('/', $requestPath);
- if ($requestMethod === "POST" && $this->rudra->request()->post()->has("_method")) {
- $this->rudra->request()->server()->set(["REQUEST_METHOD" => $this->rudra->request()->post()->get("_method")]);
- }
+ [$uri, $params] = $this->handlePattern($route, $uriSegments);
- if (in_array($requestMethod, ["PUT", "PATCH", "DELETE"])) {
- parse_str(file_get_contents("php://input"), $data);
- $this->rudra->request()->{strtolower($requestMethod)}()->set($data);
+ if ($uri === $uriSegments) {
+ $this->setCallable($route, $params);
}
}
- /**
- * @param array $route
- * @throws RouterException
- * @throws ReflectionException
- */
- protected function handleRequestUri(array $route): void
+ protected function handleRequestMethod(): void
{
- $this->handleRequestMethod();
+ $request = $this->rudra->request();
+ $requestMethod = $request->server()->get('REQUEST_METHOD');
- if ($route['method'] == $this->rudra->request()->server()->get("REQUEST_METHOD")) {
- $requestString = parse_url(ltrim($this->rudra->request()->server()->get("REQUEST_URI"), '/'))["path"] ?? "";
- [$uri, $params] = $this->handlePattern($route, explode('/', $requestString));
+ // Spoofing метода через _method
+ if ($requestMethod === 'POST' && $request->post()->has('_method')) {
+ $spoofedMethod = strtoupper($request->post()->get('_method'));
- if (implode('/', $uri) === $requestString) {
- $this->setCallable($route, $params);
+ if (in_array($spoofedMethod, ['PUT', 'PATCH', 'DELETE'])) {
+ $requestMethod = $spoofedMethod;
+ $request->server()->set(['REQUEST_METHOD' => $spoofedMethod]);
}
}
- }
- /**
- * @param array $route
- * @param $params
- * @throws RouterException|ReflectionException
- */
- protected function setCallable(array $route, $params): void
- {
- if ($route['controller'] instanceof \Closure) {
- (is_array($params)) ? $route['controller'](...$params) : $route['controller']($params);
- exit();
- }
-
- $this->directCall($route, $params);
- }
-
- /**
- * @param $params
- * @param $action
- * @param $controller
- * @throws RouterException
- */
- protected function callAction($params, $action, $controller): void
- {
- if (isset($params) && in_array("", $params)) {
- throw new RouterException("404");
- }
-
- try {
- // Вызываем метод контроллера с параметрами или без них
- $controller->{$action}(...(empty($params) ? [] : $params));
- } catch (\ArgumentCountError $e) {
- $trace = $e->getTrace()[0];
- $this->rudra()->autowire($this->rudra()->get($trace['class']), $trace['function']);
- } catch (\TypeError $e) {
- $trace = $e->getTrace()[0];
- $this->rudra()->autowire($this->rudra()->new($trace['class']), $trace['function'], $trace['args']);
+ // Обработка PUT/PATCH/DELETE
+ if (in_array($requestMethod, ['PUT', 'PATCH', 'DELETE'])) {
+ $rawInput = file_get_contents('php://input');
+ parse_str($rawInput, $data);
+ $request->{strtolower($requestMethod)}()->set($data);
}
}
@@ -180,6 +128,91 @@ protected function handlePattern(array $route, array $request): array
return [$uri, $params];
}
+ /**
+ * @param array $route
+ * @param $params
+ * @throws RouterException|ReflectionException
+ */
+ protected function setCallable(array $route, $params): void
+ {
+ if ($route['controller'] instanceof \Closure) {
+ if (is_array($params)) {
+ $route['controller'](...$params);
+ } else {
+ $route['controller']($params);
+ }
+
+ exit();
+ }
+
+ $this->directCall($route, $params);
+ }
+
+ /**
+ * @param array $route
+ * @param $params
+ * @return void
+ */
+ public function directCall(array $route, $params = null): void
+ {
+ $controller = $this->rudra->get($route['controller']);
+ $action = $route['action'];
+
+ if (!method_exists($controller, $action)) {
+ throw new RouterException("503");
+ }
+
+ // Bootstrap controller
+ $controller->shipInit();
+ $controller->containerInit();
+ $controller->init();
+
+ $controller->before();
+
+ if (isset($route['middleware']['before'])) {
+ $this->handleMiddleware($route['middleware']['before']);
+ }
+
+ $this->callAction($params, $action, $controller);
+
+ if (isset($route['middleware']['after'])) {
+ $this->handleMiddleware($route['middleware']['after']);
+ }
+
+ $controller->after();
+
+ if ($this->rudra->config()->get('environment') !== 'test') {
+ exit();
+ }
+ }
+
+ /**
+ * @param $params
+ * @param $action
+ * @param $controller
+ * @return void
+ */
+ protected function callAction($params, $action, $controller): void
+ {
+ if (isset($params) && in_array('', $params)) { //Проверка на пустой элемент
+ throw new RouterException("404");
+ }
+
+ try {
+ if (empty($params)) {
+ $controller->$action(); //Без параметров
+ } else {
+ $controller->$action(...$params); //С параметрами
+ }
+ } catch (\ArgumentCountError $e) {
+ $trace = $e->getTrace()[0];
+ $this->rudra()->autowire($this->rudra()->get($trace['class']), $trace['function']);
+ } catch (\TypeError $e) {
+ $trace = $e->getTrace()[0];
+ $this->rudra()->autowire($this->rudra()->new($trace['class']), $trace['function'], $trace['args']);
+ }
+ }
+
/**
* @param array $chainOfMiddlewares
*/
@@ -188,14 +221,27 @@ public function handleMiddleware(array $chainOfMiddlewares): void
if (!$chainOfMiddlewares) {
return;
}
-
+
$current = array_shift($chainOfMiddlewares);
- if ((is_array($current)) && count($current) === 2) {
- (new $current[0]())($current[1], $chainOfMiddlewares);
+ if (is_array($current) && count($current) === 2 && is_string($current[0])) {
+ $middleware = new $current[0]();
+ $middleware($current[1], $chainOfMiddlewares);
+ return;
+ }
+
+ if (is_array($current) && is_string($current[0])) {
+ $middleware = new $current[0]();
+ $middleware($chainOfMiddlewares);
+ return;
+ }
+
+ if (is_string($current)) {
+ $middleware = new $current();
+ $middleware($chainOfMiddlewares);
return;
}
- (is_array($current)) ? (new $current[0]())($chainOfMiddlewares) : (new $current())($chainOfMiddlewares);
+ throw new \InvalidArgumentException('Invalid middleware format');
}
}
diff --git a/src/RouterFacade.php b/src/RouterFacade.php
index dea7c09..103f7ef 100755
--- a/src/RouterFacade.php
+++ b/src/RouterFacade.php
@@ -3,8 +3,8 @@
declare(strict_types=1);
/**
- * @author : Jagepard
- * @license https://mit-license.org/ MIT
+ * @author : Jagepard
+ * @license https://mit-license.org/ MIT
*/
namespace Rudra\Router;
diff --git a/src/RouterInterface.php b/src/RouterInterface.php
index 8aa6c49..0432b5c 100755
--- a/src/RouterInterface.php
+++ b/src/RouterInterface.php
@@ -3,8 +3,8 @@
declare(strict_types=1);
/**
- * @author : Jagepard
- * @license https://mit-license.org/ MIT
+ * @author : Jagepard
+ * @license https://mit-license.org/ MIT
*/
namespace Rudra\Router;
diff --git a/src/Routing.php b/src/Routing.php
index 1d4983f..0f19815 100755
--- a/src/Routing.php
+++ b/src/Routing.php
@@ -1,5 +1,10 @@
+ * @license https://mit-license.org/ MIT
+ */
+
namespace Rudra\Router;
#[\Attribute]
diff --git a/src/Traits/RouterAnnotationTrait.php b/src/Traits/RouterAnnotationTrait.php
index 01a9072..6582487 100755
--- a/src/Traits/RouterAnnotationTrait.php
+++ b/src/Traits/RouterAnnotationTrait.php
@@ -3,8 +3,8 @@
declare(strict_types=1);
/**
- * @author : Jagepard
- * @license https://mit-license.org/ MIT
+ * @author : Jagepard
+ * @license https://mit-license.org/ MIT
*/
namespace Rudra\Router\Traits;
@@ -20,53 +20,53 @@ trait RouterAnnotationTrait
* @param boolean $attributes
* @return void
*/
- public function annotationCollector(array $controllers, bool $getter = false, bool $attributes = false)
+ public function annotationCollector(array $controllers, bool $getter = false, bool $attributes = false): ?array
{
- $annotations = [];
+ $annotations = [];
+ $annotationService = $this->rudra->get(Annotation::class);
foreach ($controllers as $controller) {
- if (class_exists($controller)) {
- $actions = get_class_methods($controller);
- } else {
+ if (!class_exists($controller)) {
throw new \Exception("Удалите контроллер $controller из файла routes.php");
}
- foreach ($actions as $action) {
- $annotation = ($attributes)
- ? $this->rudra->get(Annotation::class)->getAttributes($controller, $action)
- : $this->rudra->get(Annotation::class)->getAnnotations($controller, $action);
+ $reflection = new \ReflectionClass($controller);
+ $methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
+
+ foreach ($methods as $method) {
+ $action = $method->getName();
+ $annotation = $attributes
+ ? $annotationService->getAttributes($controller, $action)
+ : $annotationService->getAnnotations($controller, $action);
$middleware = [];
if (isset($annotation["Middleware"])) {
- $middleware = array_merge($middleware, ['before' => $this->handleAnnotationMiddleware($annotation["Middleware"])]);
+ $middleware['before'] = $this->handleAnnotationMiddleware($annotation["Middleware"]);
}
if (isset($annotation["AfterMiddleware"])) {
- $middleware = array_merge($middleware, ['after' => $this->handleAnnotationMiddleware($annotation["AfterMiddleware"])]);
+ $middleware['after'] = $this->handleAnnotationMiddleware($annotation["AfterMiddleware"]);
}
if (isset($annotation["Routing"])) {
foreach ($annotation["Routing"] as $route) {
-
- $route['controller'] = $controller;
- $route['action'] = $action;
- $route['middleware'] = $middleware;
- $route['method'] = $route['method'] ?? "GET";
-
- if ($getter) {
- $annotations[] = [$route];
- } else {
- $this->set($route);
- }
+ $route += [
+ 'controller' => $controller,
+ 'action' => $action,
+ 'middleware' => $middleware,
+ 'method' => 'GET',
+ ];
+
+ $getter
+ ? $annotations[] = [$route]
+ : $this->set($route);
}
}
}
}
- if ($getter) {
- return $annotations;
- }
+ return $getter ? $annotations : null;
}
/**
@@ -76,18 +76,15 @@ public function annotationCollector(array $controllers, bool $getter = false, bo
protected function handleAnnotationMiddleware(array $annotation): array
{
$middleware = [];
- $count = count($annotation);
-
- for ($i = 0; $i < $count; $i++) {
- $middleware[$i][] = $annotation[$i]["name"];
- if (isset($annotation[$i]["params"])) {
- $middleware[$i][] = $annotation[$i]["params"];
+ foreach ($annotation as $item) {
+ $entry = [$item['name']];
+ if (isset($item['params'])) {
+ $entry[] = $item['params'];
}
+ $middleware[] = $entry;
}
return $middleware;
}
-
- abstract public function rudra(): RudraInterface;
}
diff --git a/src/Traits/RouterRequestMethodTrait.php b/src/Traits/RouterRequestMethodTrait.php
index 7cd6dec..f4323ec 100755
--- a/src/Traits/RouterRequestMethodTrait.php
+++ b/src/Traits/RouterRequestMethodTrait.php
@@ -3,120 +3,67 @@
declare(strict_types=1);
/**
- * @author : Jagepard
- * @license https://mit-license.org/ MIT
+ * @author : Jagepard
+ * @license https://mit-license.org/ MIT
*/
namespace Rudra\Router\Traits;
-use Rudra\Container\Interfaces\RudraInterface;
-
trait RouterRequestMethodTrait
{
/**
- * @param array $route
- * @return void
+ * @param array $route
*/
- public function get(array $route): void
- {
- $route['method'] = "GET";
- $this->set($route);
- }
+ abstract public function set(array $route): void;
- /**
- * @param array $route
- * @return void
- */
- public function post(array $route): void
- {
- $route['method'] = "POST";
- $this->set($route);
- }
+ public function get(array $route): void { $route['method'] = 'GET'; $this->set($route); }
+ public function post(array $route): void { $route['method'] = 'POST'; $this->set($route); }
+ public function put(array $route): void { $route['method'] = 'PUT'; $this->set($route); }
+ public function patch(array $route): void { $route['method'] = 'PATCH'; $this->set($route); }
+ public function delete(array $route): void { $route['method'] = 'DELETE'; $this->set($route); }
- /**
- * @param array $route
- * @return void
- */
- public function put(array $route): void
- {
- $route['method'] = "PUT";
- $this->set($route);
- }
-
- /**
- * @param array $route
- * @return void
- */
- public function patch(array $route): void
- {
- $route['method'] = "PATCH";
+ public function any(array $route): void {
+ $route['method'] = 'GET|POST|PUT|PATCH|DELETE';
$this->set($route);
}
/**
- * @param array $route
- * @return void
- */
- public function delete(array $route): void
- {
- $route['method'] = "DELETE";
- $this->set($route);
- }
-
- /**
- * @param array $route
- * @return void
- */
- public function any(array $route): void
- {
- $route['method'] = "GET|POST|PUT|PATCH|DELETE";
- $this->set($route);
- }
-
- /**
- * @param array $route
- * @param array $actions
- * @return void
+ * @param array $route
+ * @param array $actions
*/
- public function resource(array $route, array $actions = ["read", "create", "update", "delete"]): void
+ public function resource(array $route, array $actions = ['read', 'create', 'update', 'delete']): void
{
- switch ($this->rudra->request()->server()->get("REQUEST_METHOD")) {
- case "GET":
- $route['method'] = "GET";
- $route['action'] = $actions[0];
-
- $this->set($route);
+ $request = $this->rudra->request();
+ $server = $request->server();
+ $post = $request->post();
+
+ $requestMethod = $server->get('REQUEST_METHOD');
+ $httpMethod = $requestMethod === 'POST' && $post->has('_method')
+ ? strtoupper($post->get('_method'))
+ : $requestMethod;
+
+ switch ($httpMethod) {
+ case 'GET':
+ $route['method'] = 'GET';
+ $route['action'] = $actions[0]; // read
break;
- case "POST":
- $actionKey = ["GET" => 0, "POST" => 1, "PUT" => 2, "PATCH" => 2, "DELETE" => 3];
- $httpMethod = ($this->rudra->request()->post()->has("_method")) ? $this->rudra->request()->post()->get("_method") : "POST";
- $route['method'] = $httpMethod;
- $route['action'] = $actions[$actionKey[$httpMethod]];
-
- $this->set($route);
+ case 'POST':
+ $route['method'] = 'POST';
+ $route['action'] = $actions[1]; // create
break;
- case "PUT":
- $route['method'] = "PUT";
- $route['action'] = $actions[2];
-
- $this->set($route);
+ case 'PUT':
+ case 'PATCH':
+ $route['method'] = $httpMethod;
+ $route['action'] = $actions[2]; // update
break;
- case "DELETE":
- $route['method'] = "DELETE";
- $route['action'] = $actions[3];
-
- $this->set($route);
+ case 'DELETE':
+ $route['method'] = 'DELETE';
+ $route['action'] = $actions[3]; // delete
break;
+ default:
+ return; // Неизвестный метод — игнорируем
}
- }
-
- /**
- * @param array $route
- */
- abstract public function set(array $route): void;
- /**
- * @return RudraInterface
- */
- abstract public function rudra(): RudraInterface;
+ $this->set($route);
+ }
}
diff --git a/tests/RouterAnnotationTraitTest.php b/tests/RouterAnnotationTraitTest.php
index 5a95ce9..659e39c 100755
--- a/tests/RouterAnnotationTraitTest.php
+++ b/tests/RouterAnnotationTraitTest.php
@@ -1,8 +1,8 @@
- * @license https://mit-license.org/ MIT
+ * @author : Jagepard
+ * @license https://mit-license.org/ MIT
*/
namespace Rudra\Router\Tests;
@@ -22,36 +22,36 @@ class RouterAnnotationTraitTest extends PHPUnit_Framework_TestCase
// Rudra::set([Annotation::class, Annotation::class]);
// Router::setNamespace("Rudra\\Router\\Tests\\Stub\\");
// }
-//
+
// public function testAnnotation()
// {
// $_SERVER["REQUEST_URI"] = "test/123";
// $_SERVER["REQUEST_METHOD"] = "GET";
-//
+
// $this->setContainer();
// Router::annotation("MainController", "actionIndex");
// $this->assertEquals("actionIndex", Rudra::config()->get("actionIndex"));
// }
-//
+
// public function testAnnotationCollector()
// {
// $_SERVER["REQUEST_URI"] = "test/123";
// $_SERVER["REQUEST_METHOD"] = "GET";
-//
+
// $this->setContainer();
// Router::annotationCollector([["MainController", "actionIndex"]]);
-//
+
// $this->assertEquals("actionIndex", Rudra::config()->get("actionIndex"));
// }
-//
+
// public function testAnnotationCollectorMultilevel()
// {
// $_SERVER["REQUEST_URI"] = "test/123";
// $_SERVER["REQUEST_METHOD"] = "GET";
-//
+
// $this->setContainer();
// Router::annotationCollector(["blog" => ["MainController", "actionIndex"]]);
-//
+
// $this->assertEquals("actionIndex", Rudra::config()->get("actionIndex"));
// }
}
diff --git a/tests/stub/Controllers/MainController.php b/tests/stub/Controllers/MainController.php
deleted file mode 100755
index a2bbb0c..0000000
--- a/tests/stub/Controllers/MainController.php
+++ /dev/null
@@ -1,69 +0,0 @@
-set(["actionIndex" => "actionIndex"]);
- }
-
- public function actionGet()
- {
- Rudra::config()->set(["actionGet" => "GET"]);
- }
-
- public function actionPost()
- {
- Rudra::config()->set(["actionPost" => "POST"]);
- }
-
- public function actionPut()
- {
- Rudra::config()->set(["actionPut" => "PUT"]);
- }
-
- public function actionPatch()
- {
- Rudra::config()->set(["actionPatch" => "PATCH"]);
- }
-
- public function actionDelete()
- {
- Rudra::config()->set(["actionDelete" => "DELETE"]);
- }
-
- public function actionAny()
- {
- Rudra::config()->set(["actionAny" => "ANY"]);
- }
-
- public function read($params = null)
- {
- Rudra::config()->set(["read" => "read"]);
- }
-
- public function create()
- {
- Rudra::config()->set(["create" => "create"]);
- }
-
- public function update($params)
- {
- Rudra::config()->set(["update" => "update"]);
- }
-
- public function delete($params)
- {
- Rudra::config()->set(["delete" => "delete"]);
- }
-
- public function shipInit() {}
- public function containerInit() {}
- public function init() {}
- public function before() {}
- public function after() {}
-}
diff --git a/tests/stub/Middleware/Middleware.php b/tests/stub/Middleware/Middleware.php
deleted file mode 100755
index e95e5fe..0000000
--- a/tests/stub/Middleware/Middleware.php
+++ /dev/null
@@ -1,13 +0,0 @@
-set(["middleware" => Middleware::class]);
- }
-}
diff --git a/tests/stub/route.php b/tests/stub/route.php
deleted file mode 100755
index fe79957..0000000
--- a/tests/stub/route.php
+++ /dev/null
@@ -1,17 +0,0 @@
-setNamespace($namespace);
-
- // Routes
-
- return false;
- }
-}