|
@@ -20,11 +20,11 @@ class IoC {
|
|
|
* Register an object and its resolver.
|
|
|
*
|
|
|
* @param string $name
|
|
|
- * @param Closure $resolver
|
|
|
+ * @param mixed $resolver
|
|
|
* @param bool $singleton
|
|
|
* @return void
|
|
|
*/
|
|
|
- public static function register($name, Closure $resolver, $singleton = false)
|
|
|
+ public static function register($name, $resolver, $singleton = false)
|
|
|
{
|
|
|
static::$registry[$name] = compact('resolver', 'singleton');
|
|
|
}
|
|
@@ -72,70 +72,122 @@ class IoC {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Register a controller with the IoC container.
|
|
|
- *
|
|
|
- * @param string $name
|
|
|
- * @param Closure $resolver
|
|
|
- * @return void
|
|
|
- */
|
|
|
- public static function controller($name, $resolver)
|
|
|
- {
|
|
|
- static::register("controller: {$name}", $resolver);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Resolve a core Laravel class from the container.
|
|
|
+ * Resolve a given type to an instance.
|
|
|
*
|
|
|
* <code>
|
|
|
- * // Resolve the "laravel.router" class from the container
|
|
|
- * $input = IoC::core('router');
|
|
|
+ * // Get an instance of the "mailer" object registered in the container
|
|
|
+ * $mailer = IoC::resolve('mailer');
|
|
|
*
|
|
|
- * // Equivalent resolution of the router using the "resolve" method
|
|
|
- * $input = IoC::resolve('laravel.router');
|
|
|
+ * // Get an instance of the "mailer" object and pass parameters to the resolver
|
|
|
+ * $mailer = IoC::resolve('mailer', array('test'));
|
|
|
* </code>
|
|
|
*
|
|
|
- * @param string $name
|
|
|
- * @param array $parameters
|
|
|
+ * @param string $type
|
|
|
* @return mixed
|
|
|
*/
|
|
|
- public static function core($name, $parameters = array())
|
|
|
+ public static function resolve($type, $parameters = array())
|
|
|
{
|
|
|
- return static::resolve("laravel.{$name}", $parameters);
|
|
|
+ // If an instance of the type is currently being managed as a singleton, we will
|
|
|
+ // just return the existing instance instead of instantiating a fresh instance
|
|
|
+ // so the developer can keep re-using the exact same object instance from us.
|
|
|
+ if (isset(static::$singletons[$type]))
|
|
|
+ {
|
|
|
+ return static::$singletons[$type];
|
|
|
+ }
|
|
|
+
|
|
|
+ $concrete = array_get(static::$registry, "{$type}.resolver", $type);
|
|
|
+
|
|
|
+ // We're ready to instantiate an instance of the concrete type registered for
|
|
|
+ // the binding. This will instantiate the type, as well as resolve any of
|
|
|
+ // its nested dependencies recursively until they are each resolved.
|
|
|
+ if ($concrete == $type or $concrete instanceof Closure)
|
|
|
+ {
|
|
|
+ $object = static::build($concrete);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ $object = static::resolve($concrete);
|
|
|
+ }
|
|
|
+
|
|
|
+ // If the requested type is registered as a singleton, we want to cache off
|
|
|
+ // the instance in memory so we can return it later without creating an
|
|
|
+ // entirely new instances of the object on each subsequent request.
|
|
|
+ if (isset(static::$registry[$type]['singleton']))
|
|
|
+ {
|
|
|
+ static::$singletons[$type] = $object;
|
|
|
+ }
|
|
|
+
|
|
|
+ return $object;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Resolve an object instance from the container.
|
|
|
- *
|
|
|
- * <code>
|
|
|
- * // Get an instance of the "mailer" object registered in the container
|
|
|
- * $mailer = IoC::resolve('mailer');
|
|
|
- *
|
|
|
- * // Get an instance of the "mailer" object and pass parameters to the resolver
|
|
|
- * $mailer = IoC::resolve('mailer', array('test'));
|
|
|
- * </code>
|
|
|
+ * Instantiate an instance of the given type.
|
|
|
*
|
|
|
- * @param string $name
|
|
|
+ * @param string $type
|
|
|
* @param array $parameters
|
|
|
* @return mixed
|
|
|
*/
|
|
|
- public static function resolve($name, $parameters = array())
|
|
|
+ protected static function build($type, $parameters = array())
|
|
|
{
|
|
|
- if (array_key_exists($name, static::$singletons))
|
|
|
+ // If the concrete type is actually a Closure, we will just execute it and
|
|
|
+ // hand back the results of the function, which allows functions to be
|
|
|
+ // used as resolvers for more fine-tuned resolution of the objects.
|
|
|
+ if ($type instanceof Closure)
|
|
|
{
|
|
|
- return static::$singletons[$name];
|
|
|
+ return call_user_func_array($type, $parameters);
|
|
|
}
|
|
|
|
|
|
- $object = call_user_func_array(static::$registry[$name]['resolver'], $parameters);
|
|
|
+ $reflector = new \ReflectionClass($type);
|
|
|
|
|
|
- // If the resolver is registering as a singleton resolver, we will cache
|
|
|
- // the instance of the object in the container so we can resolve it next
|
|
|
- // time without having to instantiate a brand new instance.
|
|
|
- if (static::$registry[$name]['singleton'])
|
|
|
+ // If the type is not instantiable, the developer is attempting to resolve
|
|
|
+ // an abstract type such as an Interface of Abstract Class and there is
|
|
|
+ // no binding registered for the abstraction so we need to bail out.
|
|
|
+ if ( ! $reflector->isInstantiable())
|
|
|
{
|
|
|
- return static::$singletons[$name] = $object;
|
|
|
+ throw new Exception("Resolution target [$type] is not instantiable.");
|
|
|
}
|
|
|
|
|
|
- return $object;
|
|
|
+ $constructor = $reflector->getConstructor();
|
|
|
+
|
|
|
+ // If there is no constructor, that means there are no dependencies and
|
|
|
+ // we can just resolve an instance of the object right away without
|
|
|
+ // resolving any other types or dependencies from the container.
|
|
|
+ if (is_null($constructor))
|
|
|
+ {
|
|
|
+ return new $type;
|
|
|
+ }
|
|
|
+
|
|
|
+ $dependencies = static::dependencies($constructor->getParameters());
|
|
|
+
|
|
|
+ return $reflector->newInstanceArgs($dependencies);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Resolve all of the dependencies from the ReflectionParameters.
|
|
|
+ *
|
|
|
+ * @param array $parameterrs
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ protected static function dependencies($parameters)
|
|
|
+ {
|
|
|
+ $dependencies = array();
|
|
|
+
|
|
|
+ foreach ($parameters as $parameter)
|
|
|
+ {
|
|
|
+ $dependency = $parameter->getClass();
|
|
|
+
|
|
|
+ // If the class is null, it means the dependency is a string or some other
|
|
|
+ // primitive type, which we can not esolve 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))
|
|
|
+ {
|
|
|
+ throw new Exception("Unresolvable dependency resolving [$parameter].");
|
|
|
+ }
|
|
|
+
|
|
|
+ $dependencies[] = static::resolve($dependency->name);
|
|
|
+ }
|
|
|
+
|
|
|
+ return (array) $dependencies;
|
|
|
}
|
|
|
|
|
|
}
|