Finalize routing with injection and parameters

diff --git a/app/Controller/HelloWorldController.php b/app/Controller/HelloWorldController.php
index 7f2af8b..86c5b8e 100644
--- a/app/Controller/HelloWorldController.php
+++ b/app/Controller/HelloWorldController.php
@@ -28,13 +28,13 @@ class HelloWorldController
         return new GenericResponse('Hello World!');
     }

-    #[Route('/routes')]
-    public function routes(RouterConfig $config): ResponseInterface
+    #[Route('/routes/{word}')]
+    public function routes(RouterConfig $config, string $word): ResponseInterface
     {
         $routes = implode('<br>', array_map(
-            fn($route) => sprintf('%s - %s->%s', $route->getRoute()->path, $route->getController(), $route->getMethod()),
-            $config->getRoutes()
-        ));
+                fn($route) => sprintf('%s - %s->%s', $route->getRoute()->path, $route->getController(), $route->getMethod()),
+                $config->getRoutes()
+            )) . "<br>$word";

         return new GenericResponse($routes);
     }
diff --git a/src/Container/ContainerInterface.php b/src/Container/ContainerInterface.php
index 7b55a94..5119eb5 100644
--- a/src/Container/ContainerInterface.php
+++ b/src/Container/ContainerInterface.php
@@ -19,4 +19,6 @@ interface ContainerInterface
      * @throws ClassNotFoundException
      */
     public function get(string $className): object;
+
+    public function call(string $className, string $methodName, array $parameters = []): mixed;
 }
\ No newline at end of file
diff --git a/src/Container/GenericContainer.php b/src/Container/GenericContainer.php
index 8fdb26e..0e467b6 100644
--- a/src/Container/GenericContainer.php
+++ b/src/Container/GenericContainer.php
@@ -2,8 +2,10 @@

 namespace Ardent\Undercurrent\Container;

+use Ardent\Undercurrent\Http\RouteConfig;
 use Exception;
 use ReflectionClass;
+use ReflectionMethod;

 class GenericContainer implements ContainerInterface
 {
@@ -61,23 +63,39 @@ class GenericContainer implements ContainerInterface
         return $instance;
     }

+    public function call(string $className, string $methodName, array $parameters = []): mixed
+    {
+        $params = $this->methodParams($className, $methodName, $parameters) + $parameters;
+        return $this->get($className)->$methodName(...$params);
+    }
+
     private function autowire(string $className): ?object
     {
         $reflection = new ReflectionClass($className);
-        $constructor = $reflection->getConstructor();
-        if (!$constructor) {
+        $reflectionMethod = $reflection->getConstructor();
+        if (!$reflectionMethod) {
             return new $className();
         }

+        return new $className(...$this->methodParams($className, $reflectionMethod->getName()));
+    }
+
+    private function methodParams(string $className, string $methodName, array $exceptParams = []): array
+    {
+        $reflectionMethod = new ReflectionMethod($className, $methodName);
+
         $params = [];
-        foreach ($constructor->getParameters() as $parameter) {
+        foreach ($reflectionMethod->getParameters() as $parameter) {
+            if (in_array($parameter->getName(), array_keys($exceptParams))) {
+                continue;
+            }
             $type = $parameter->getType();
             if (!$type) {
-                throw new Exception("Parameter {$parameter->getName()} in $className has no type");
+                throw new Exception('Cannot autowire parameter without type');
             }
             $params[] = $this->get($type->getName());
         }

-        return new $className(...$params);
+        return $params;
     }
 }
\ No newline at end of file
diff --git a/src/Http/GenericRouter.php b/src/Http/GenericRouter.php
index d5ffb95..334ecac 100644
--- a/src/Http/GenericRouter.php
+++ b/src/Http/GenericRouter.php
@@ -17,7 +17,7 @@ class GenericRouter implements RouterInterface
     }

     /**
-     * @throws RouteNotFoundException|ClassNotFoundException
+     * @throws RouteNotFoundException
      */
     public function dispatch(RequestInterface $request): ResponseInterface
     {
@@ -28,11 +28,11 @@ class GenericRouter implements RouterInterface
                 continue;
             }

-            $controller = $this->container->get($route->getController());
-            $method = $route->getMethod();
-//            $params = $this->autowire($route) + $this->resolveParams($route->getRoute()->path, $request->getUri());
-            $params = $this->resolveParams($route->getRoute()->path, $request->getUri());
-            return $controller->$method(...$params);
+            return $this->container->call(
+                $route->getController(),
+                $route->getMethod(),
+                $params,
+            );
         }

         throw new RouteNotFoundException($request);
@@ -40,6 +40,10 @@ class GenericRouter implements RouterInterface

     private function resolveParams(string $routeUri, string $requestUri): ?array
     {
+        if ($routeUri === $requestUri) {
+            return [];
+        }
+
         $result = preg_match_all('/{(\w+)}/', $routeUri, $tokens);

         if (!$result) {
@@ -55,27 +59,11 @@ class GenericRouter implements RouterInterface
             ) . '$/';

         $result = preg_match($matchingRegex, $requestUri, $matches);
-        if ($result === 0) {
-            return [];
+        if (!$result) {
+            return null;
         }
         $matches = array_slice($matches, 1);

         return array_combine(array_map(fn($token) => trim($token, '{}'), $tokens), $matches);
     }
-
-    private function autowire(RouteConfig $route): array
-    {
-        $reflectionMethod = new ReflectionMethod($route->getController(), $route->getMethod());
-
-        $params = [];
-        foreach ($reflectionMethod->getParameters() as $parameter) {
-            $type = $parameter->getType();
-            if (!$type) {
-                throw new Exception('Cannot autowire parameter without type');
-            }
-            $params[] = $this->container->get($type->getName());
-        }
-
-        return $params;
-    }
 }
\ No newline at end of file
This commit is contained in:
Tim 2023-08-10 17:57:25 +02:00
parent 2fd6e50b90
commit 42c590dfd6
4 changed files with 42 additions and 34 deletions

View File

@ -28,13 +28,13 @@ class HelloWorldController
return new GenericResponse('Hello World!'); return new GenericResponse('Hello World!');
} }
#[Route('/routes')] #[Route('/routes/{word}')]
public function routes(RouterConfig $config): ResponseInterface public function routes(RouterConfig $config, string $word): ResponseInterface
{ {
$routes = implode('<br>', array_map( $routes = implode('<br>', array_map(
fn($route) => sprintf('%s - %s->%s', $route->getRoute()->path, $route->getController(), $route->getMethod()), fn($route) => sprintf('%s - %s->%s', $route->getRoute()->path, $route->getController(), $route->getMethod()),
$config->getRoutes() $config->getRoutes()
)); )) . "<br>$word";
return new GenericResponse($routes); return new GenericResponse($routes);
} }

View File

@ -19,4 +19,6 @@ interface ContainerInterface
* @throws ClassNotFoundException * @throws ClassNotFoundException
*/ */
public function get(string $className): object; public function get(string $className): object;
public function call(string $className, string $methodName, array $parameters = []): mixed;
} }

View File

@ -2,8 +2,10 @@
namespace Ardent\Undercurrent\Container; namespace Ardent\Undercurrent\Container;
use Ardent\Undercurrent\Http\RouteConfig;
use Exception; use Exception;
use ReflectionClass; use ReflectionClass;
use ReflectionMethod;
class GenericContainer implements ContainerInterface class GenericContainer implements ContainerInterface
{ {
@ -61,23 +63,39 @@ class GenericContainer implements ContainerInterface
return $instance; return $instance;
} }
public function call(string $className, string $methodName, array $parameters = []): mixed
{
$params = $this->methodParams($className, $methodName, $parameters) + $parameters;
return $this->get($className)->$methodName(...$params);
}
private function autowire(string $className): ?object private function autowire(string $className): ?object
{ {
$reflection = new ReflectionClass($className); $reflection = new ReflectionClass($className);
$constructor = $reflection->getConstructor(); $reflectionMethod = $reflection->getConstructor();
if (!$constructor) { if (!$reflectionMethod) {
return new $className(); return new $className();
} }
return new $className(...$this->methodParams($className, $reflectionMethod->getName()));
}
private function methodParams(string $className, string $methodName, array $exceptParams = []): array
{
$reflectionMethod = new ReflectionMethod($className, $methodName);
$params = []; $params = [];
foreach ($constructor->getParameters() as $parameter) { foreach ($reflectionMethod->getParameters() as $parameter) {
if (in_array($parameter->getName(), array_keys($exceptParams))) {
continue;
}
$type = $parameter->getType(); $type = $parameter->getType();
if (!$type) { if (!$type) {
throw new Exception("Parameter {$parameter->getName()} in $className has no type"); throw new Exception('Cannot autowire parameter without type');
} }
$params[] = $this->get($type->getName()); $params[] = $this->get($type->getName());
} }
return new $className(...$params); return $params;
} }
} }

View File

@ -17,7 +17,7 @@ class GenericRouter implements RouterInterface
} }
/** /**
* @throws RouteNotFoundException|ClassNotFoundException * @throws RouteNotFoundException
*/ */
public function dispatch(RequestInterface $request): ResponseInterface public function dispatch(RequestInterface $request): ResponseInterface
{ {
@ -28,11 +28,11 @@ class GenericRouter implements RouterInterface
continue; continue;
} }
$controller = $this->container->get($route->getController()); return $this->container->call(
$method = $route->getMethod(); $route->getController(),
// $params = $this->autowire($route) + $this->resolveParams($route->getRoute()->path, $request->getUri()); $route->getMethod(),
$params = $this->resolveParams($route->getRoute()->path, $request->getUri()); $params,
return $controller->$method(...$params); );
} }
throw new RouteNotFoundException($request); throw new RouteNotFoundException($request);
@ -40,6 +40,10 @@ class GenericRouter implements RouterInterface
private function resolveParams(string $routeUri, string $requestUri): ?array private function resolveParams(string $routeUri, string $requestUri): ?array
{ {
if ($routeUri === $requestUri) {
return [];
}
$result = preg_match_all('/{(\w+)}/', $routeUri, $tokens); $result = preg_match_all('/{(\w+)}/', $routeUri, $tokens);
if (!$result) { if (!$result) {
@ -55,27 +59,11 @@ class GenericRouter implements RouterInterface
) . '$/'; ) . '$/';
$result = preg_match($matchingRegex, $requestUri, $matches); $result = preg_match($matchingRegex, $requestUri, $matches);
if ($result === 0) { if (!$result) {
return []; return null;
} }
$matches = array_slice($matches, 1); $matches = array_slice($matches, 1);
return array_combine(array_map(fn($token) => trim($token, '{}'), $tokens), $matches); return array_combine(array_map(fn($token) => trim($token, '{}'), $tokens), $matches);
} }
private function autowire(RouteConfig $route): array
{
$reflectionMethod = new ReflectionMethod($route->getController(), $route->getMethod());
$params = [];
foreach ($reflectionMethod->getParameters() as $parameter) {
$type = $parameter->getType();
if (!$type) {
throw new Exception('Cannot autowire parameter without type');
}
$params[] = $this->container->get($type->getName());
}
return $params;
}
} }