Browse Source

Merge pull request #1690 from kdocki/master

IoC container not resolving classes with optional parameters (i.e. models that use Eloquent)
Taylor Otwell 11 years ago
parent
commit
2e8b5575e5
2 changed files with 114 additions and 9 deletions
  1. 35 9
      laravel/ioc.php
  2. 79 0
      laravel/tests/cases/ioc.test.php

+ 35 - 9
laravel/ioc.php

@@ -172,7 +172,7 @@ class IoC {
 			return new $type;
 		}
 
-		$dependencies = static::dependencies($constructor->getParameters());
+		$dependencies = static::dependencies($constructor->getParameters(), $parameters);
 
 		return $reflector->newInstanceArgs($dependencies);
 	}
@@ -181,9 +181,10 @@ class IoC {
 	 * Resolve all of the dependencies from the ReflectionParameters.
 	 *
 	 * @param  array  $parameters
+	 * @param  array  $arguments that might have been passed into our resolve
 	 * @return array
 	 */
-	protected static function dependencies($parameters)
+	protected static function dependencies($parameters, $arguments)
 	{
 		$dependencies = array();
 
@@ -191,18 +192,43 @@ class IoC {
 		{
 			$dependency = $parameter->getClass();
 
-			// If the class is null, it means the dependency is a string or some other
-			// primitive type, which we can not resolve since it is not a class and
-			// we'll just bomb out with an error since we have nowhere to go.
-			if (is_null($dependency))
+			// If the person passed in some parameters to the class
+			// then we should probably use those instead of trying 
+			// to resolve a new instance of the class
+			if (count($arguments) > 0)
 			{
-				throw new \Exception("Unresolvable dependency resolving [$parameter].");
+				$dependencies[] = array_shift($arguments);
+			}
+			else if (is_null($dependency))
+			{
+				$dependency[] = static::resolveNonClass($parameter);
+			}
+			else
+			{
+				$dependencies[] = static::resolve($dependency->name);				
 			}
-
-			$dependencies[] = static::resolve($dependency->name);
 		}
 
 		return (array) $dependencies;
 	}
 
+	/**
+	 * Resolves optional parameters for our dependency injection
+	 * pretty much took backport straight from L4's Illuminate\Container
+	 *
+	 * @param ReflectionParameter
+	 * @return default value
+	 */
+	protected static function resolveNonClass($parameter)
+	{
+		if ($parameter->isDefaultValueAvailable())
+		{
+			return $parameter->getDefaultValue();
+		}
+		else
+		{
+			throw new \Exception("Unresolvable dependency resolving [$parameter].");
+		}
+	}	
+
 }

+ 79 - 0
laravel/tests/cases/ioc.test.php

@@ -1,5 +1,34 @@
 <?php
 
+/**
+ * Testing Optional Parameters in classes' Dependency Injection
+ */
+class TestOptionalParamClassForIoC
+{
+	public function __construct($optional_param = 42) {}
+}
+
+/**
+ * Testing Dependency Injection with this class
+ */
+class TestClassOneForIoC
+{
+	public $_variable;
+}
+
+/**
+ * Testing Dependency Injection of ClassOne
+ */
+class TestClassTwoForIoC
+{
+	public $class_one;
+	public function __construct(TestClassOneForIoC $class_one)
+	{
+		$this->class_one = $class_one;
+	}
+}
+
+
 class IoCTest extends PHPUnit_Framework_TestCase {
 
 	/**
@@ -71,4 +100,54 @@ class IoCTest extends PHPUnit_Framework_TestCase {
 		$this->assertTrue(IoC::registered('controller: ioc.test'));
 	}
 
+	/**
+	 * Test that classes with optional parameters can resolve
+	 */
+	public function testOptionalParamClassResolves()
+	{
+		$test = IoC::resolve('TestOptionalParamClassForIoC');
+		$this->assertInstanceOf('TestOptionalParamClassForIoC', $test);
+	}
+
+	/**
+	 * Test that we can resolve TestClassOneForIoC using IoC
+	 */
+	public function testClassOneForIoCResolves()
+	{
+		$test = IoC::resolve('TestClassOneForIoC');
+		$this->assertInstanceOf('TestClassOneForIoC', $test);
+	}
+
+	/**
+	 * Test that we can resolve TestClassTwoForIoC
+	 */
+	public function testClassTwoForIoCResolves()
+	{
+		$test = IoC::resolve('TestClassTwoForIoC');
+		$this->assertInstanceOf('TestClassTwoForIoC', $test);
+	}
+
+	/**
+	 * Test that when we resolve TestClassTwoForIoC we auto resolve
+	 * the dependency for TestClassOneForIoC
+	 */
+	public function testClassTwoResolvesClassOneDependency()
+	{
+		$test = IoC::resolve('TestClassTwoForIoC');
+		$this->assertInstanceOf('TestClassOneForIoC', $test->TestClassOneForIoC);
+	}
+
+	/**
+	 * Test that when we resolve TestClassTwoForIoC with a parameter
+	 * that it actually uses that instead of a blank class TestClassOneForIoC
+	 */
+	public function testClassTwoResolvesClassOneWithArgument()
+	{
+		$class_one = IoC::resolve('TestClassOneForIoC');
+		$class_one->test_variable = 42;
+
+		$class_two = IoC::resolve('TestClassTwoForIoC', [$class_one]);
+		$this->assertEquals(42, $class_two->class_one->test_variable);
+	}
+
 }