From 0aa514eb695847bbe5b784c27e6bf24016a22308 Mon Sep 17 00:00:00 2001
From: James Walker <jh_walker@outlook.com>
Date: Sun, 12 Nov 2023 13:48:04 +0000
Subject: [PATCH] Container::resolve() support falling back to default value
 after failing to resolve parameters for class used as parameter in class
 we're constructing

---
 src/DI/Container.php        | 21 +++++++++---------
 tests/DI/ContainerTests.php | 43 +++++++++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+), 10 deletions(-)

diff --git a/src/DI/Container.php b/src/DI/Container.php
index be1b2a8..c204f92 100644
--- a/src/DI/Container.php
+++ b/src/DI/Container.php
@@ -75,23 +75,24 @@ class Container {
 	 * @param array $args optional Constructor named arguments available
 	 * @return array
 	 */
-	public function resolve(
-		$class, $method, array $args=[]) : array {
+	public function resolve($class, $method, array $args=[]) : array {
 
 		$resolved = [];
 		$arguments = Resolver::get_method_args($class, $method);
 
-		//Iterate args
 		foreach ($arguments as $arg) {
-			//Reset value
+
 			$value = null;
 
-			//If has a type string, try to get
-			//	a class instance from the container
+			/** Type string = get a class instance from the container */
 			if ($arg -> typeStr) {
 
-				// May fail if not valid class, catch acceptable
-				// exceptions and allow continuing resolve from Resolver
+				/**
+				 * May fail if not a valid class
+				 *
+				 * We catch acceptable exceptions and allow the 
+				 * resolution attempt to continue via the Resolver.
+				 */
 				try {
 					$value = $this -> instance(
 						$arg -> typeStr,
@@ -99,8 +100,7 @@ class Container {
 						(is_string($class) ? $class : get_class($class))
 					);
 				}
-				catch (Exceptions\InvalidClassException $ex) { 
-				}
+				catch (Exceptions\InvalidClassException|Exceptions\ReflectionArgumentResolve $ex) {}
 
 			}
 
@@ -109,6 +109,7 @@ class Container {
 			}
 
 			$resolved[] = $value;
+			
 		}
 
 		return $resolved;
diff --git a/tests/DI/ContainerTests.php b/tests/DI/ContainerTests.php
index ffef221..35b3206 100644
--- a/tests/DI/ContainerTests.php
+++ b/tests/DI/ContainerTests.php
@@ -63,6 +63,38 @@ class TestClass {
 
 	}
 
+
+	/**
+	 * Argument resolution test when a class used as a parameter, with a 
+	 * default value, has its own required parameters.
+	 * 
+	 * @param ?\ArdeidaeTests\DI\TestClassWithParam $Test optional (`null`)
+	 * @return void
+	 */
+	public function resolveOptionalClassParameterHasRequiredParameters(?TestClassWithParam $Test=null) : void {
+
+		//...
+		
+	}
+
+}
+
+/**
+ * Test class that takes a constructor parameter
+ *
+ * @package Ardeidae
+ * @subpackage Tests
+ * @author James Walker
+ * @license MIT License
+ */
+class TestClassWithParam {
+
+	/**
+	 * Constructor.
+	 */
+	public function __construct(
+		public string $foo) {}
+
 }
 
 /**
@@ -443,6 +475,17 @@ class ContainerTests extends Trainline\Framework\Unit {
 	}
 
 
+	/**
+	 * Argument resolution - parameter class has a required parameter 
+	 * but a default value is available (we should use the default value 
+	 * if the class can't be constructed due to a missing parameter).
+	 */
+	public function resolveWhenOptionalClassParameterHasRequiredParameters() : void {
+		$result = $this -> getDic() -> resolve(self::TEST_CLASS, "resolveOptionalClassParameterHasRequiredParameters");
+		assertions\assrt(($result && is_null($result[0])));
+	}
+
+
 	/**
 	 * Argument resolution - including with DI instances.
 	 *
-- 
GitLab