Updated DependencyInjection component's API

Signed-off-by: Gregory PLANCHAT <g.planchat@gmail.com>
This commit is contained in:
Gregory PLANCHAT 2012-07-17 23:27:44 +02:00
commit 2bed707ecd
7 changed files with 438 additions and 63 deletions

View file

@ -10,8 +10,7 @@ class Config
public function __invoke(DependencyInjection\Factory $factory, Node $config) public function __invoke(DependencyInjection\Factory $factory, Node $config)
{ {
foreach ($config as $className => $classConfig) { foreach ($config as $className => $classConfig) {
$classDefinition = $factory->initClassDefinition($className); $factory->addClassDefinition($className);
$factory->registerClassDefinition($className, $classDefinition);
if ($classConfig->methods instanceof Node) { if ($classConfig->methods instanceof Node) {
foreach ($classConfig->methods as $methodName => $methodConfig) { foreach ($classConfig->methods as $methodName => $methodConfig) {

View file

@ -11,15 +11,17 @@ class ClassDefinition
{ {
protected $_className = null; protected $_className = null;
protected $_reflector = null; protected $_reflector = null;
protected $_methods = array(); protected $_methodDefinitions = array();
protected $_methodDefinitionHandlerClass = null; protected $_registry = null;
protected $_methodDefinitionClassName = 'Wootook\\Core\\DependencyInjection\\Definition\\MethodDefinition';
/** /**
* @param string $className * @param string $className
* @param null|string $methodDefinitionHandlerClass * @param null|string $methodDefinitionHandlerClass
*/ */
public function __construct($className, $methodDefinitionHandlerClass = null) public function __construct($className, DependencyInjection\Registry $registry = null, $methodDefinitionHandlerClass = null)
{ {
$this->_className = $className; $this->_className = $className;
try { try {
@ -35,13 +37,16 @@ class ClassDefinition
} }
} }
/** public function setRegistry(DependencyInjection\Registry $registry)
* @param string $methodName
* @return \Wootook\Core\DependencyInjection\Definition\MethodDefinition
*/
protected function _getMethodDefinitionInstance($methodName)
{ {
return new $this->_methodDefinitionHandlerClass($this, $methodName); $this->_registry = $registry;
return $this;
}
public function getRegistry()
{
return $this->_registry;
} }
/** /**
@ -49,17 +54,50 @@ class ClassDefinition
* @return \Wootook\Core\DependencyInjection\Definition\MethodDefinition * @return \Wootook\Core\DependencyInjection\Definition\MethodDefinition
* @throws \Wootook\Core\Exception\DependencyInjection\InvalidArgumentException * @throws \Wootook\Core\Exception\DependencyInjection\InvalidArgumentException
*/ */
public function getMethodDefinition($methodName) public function getMethodDefinition($methodName, $registerInstanceIfNew = false)
{ {
if (!is_string($methodName)) { if (!is_string($methodName)) {
throw new CoreException\DependencyInjection\InvalidArgumentException('Method names only accept string.'); throw new CoreException\DependencyInjection\InvalidArgumentException('Method names only accept string.');
} }
if (!isset($this->_methods[$methodName])) { if (isset($this->_methodDefinitions[$methodName])) {
$this->_methods[$methodName] = $this->_getMethodDefinitionInstance($methodName); return $this->_methodDefinitions[$methodName];
} }
return $this->_methods[$methodName]; $definition = $this->initMethodDefinition($methodName);
if ($registerInstanceIfNew === true) {
$this->registerMethodDefinition($methodName, $definition);
}
return $definition;
}
/**
* @param string $methodName
* @return \Wootook\Core\DependencyInjection\Definition\MethodDefinition
*/
public function initMethodDefinition($methodName)
{
$class = $this->getMethodDefinitionClassName();
return new $class($this, $methodName, $this->getRegistry());
}
public function registerMethodDefinition($methodName, MethodDefinition $methodDefinition)
{
if (!is_string($methodName)) {
throw new CoreException\DependencyInjection\InvalidArgumentException('Method names only accept string.');
}
$this->_methodDefinitions[$methodName] = $methodDefinition;
return $this;
}
public function addMethodDefinition($methodName)
{
$this->registerMethodDefinition($methodName, $this->initMethodDefinition($methodName));
return $this;
} }
public function setMethodDefinition($methodName, MethodDefinition $definition) public function setMethodDefinition($methodName, MethodDefinition $definition)
@ -68,17 +106,31 @@ class ClassDefinition
throw new CoreException\DependencyInjection\InvalidArgumentException('Method names only accept string.'); throw new CoreException\DependencyInjection\InvalidArgumentException('Method names only accept string.');
} }
$this->_methods[$methodName] = $definition; $this->_methodDefinitions[$methodName] = $definition;
return $this; return $this;
} }
public function getAllMethodDefinitions() public function setMethodDefinitionClassName($methodDefinitionClassName)
{ {
return $this->_methods; if (!is_string($methodDefinitionClassName)) {
throw new CoreException\DependencyInjection\InvalidArgumentException('Class names only accept string.');
}
return $this->_methodDefinitionClassName;
} }
public function newInstance(Array $args = array(), $withoutConstructorCall = false) public function getMethodDefinitionClassName()
{
return $this->_methodDefinitionClassName;
}
public function getAllMethodDefinitions()
{
return $this->_methodDefinitions;
}
public function newInstance(Array $args = array())
{ {
try { try {
if ($this->getReflector()->hasMethod('__construct')) { if ($this->getReflector()->hasMethod('__construct')) {
@ -104,7 +156,7 @@ class ClassDefinition
public function reset() public function reset()
{ {
return $this->_methods = array(); return $this->_methodDefinitions = array();
} }
public function getReflector() public function getReflector()

View file

@ -27,7 +27,7 @@ class MethodDefinition
/** /**
* @var array * @var array
*/ */
protected $_arguments = array(); protected $_argumentDefinitions = array();
/** /**
* @var array * @var array
@ -44,7 +44,7 @@ class MethodDefinition
*/ */
protected $_registry = null; protected $_registry = null;
protected $_argumentDefinitionHandlerClass = null; protected $_argumentDefinitionClassName = 'Wootook\\Core\\DependencyInjection\\Definition\\ArgumentDefinition';
/** /**
* @param ClassDefinition $classDefinition * @param ClassDefinition $classDefinition
@ -64,23 +64,12 @@ class MethodDefinition
} }
if (is_string($argumentDefinitionHandlerClass)) { if (is_string($argumentDefinitionHandlerClass)) {
$this->_argumentDefinitionHandlerClass = $argumentDefinitionHandlerClass; $this->setArgumentDefinitionClassName($argumentDefinitionHandlerClass);
} else {
$this->_argumentDefinitionHandlerClass = __NAMESPACE__ . '\\ArgumentDefinition';
} }
$this->_registry = $registry; $this->_registry = $registry;
} }
/**
* @param $argumentPosition
* @return \Wootook\Core\DependencyInjection\Definition\ArgumentDefinition
*/
protected function _getArgumentDefinitionInstance($argumentPosition)
{
return new $this->_argumentDefinitionHandlerClass($this, $argumentPosition);
}
/** /**
* @param \Wootook\Core\DependencyInjection\Registry $registry * @param \Wootook\Core\DependencyInjection\Registry $registry
* @return MethodDefinition * @return MethodDefinition
@ -100,6 +89,98 @@ class MethodDefinition
return $this->_registry; return $this->_registry;
} }
/**
* @param int|string $argumentPosition
* @return \Wootook\Core\DependencyInjection\Definition\ArgumentDefinition
* @throws \Wootook\Core\Exception\DependencyInjection\InvalidArgumentException
*/
public function getArgumentDefinition($argumentPosition, $registerInstanceIfNew = false)
{
if (is_string($argumentPosition) && isset($this->_argumentIndex[$argumentPosition])) {
$argumentPosition = $this->_argumentIndex[$argumentPosition];
}
if (!is_int($argumentPosition)) {
throw new CoreException\DependencyInjection\InvalidArgumentException('Argument could only be found by position or by name.');
}
if (isset($this->_argumentDefinitions[$argumentPosition])) {
return $this->_argumentDefinitions[$argumentPosition];
}
$definition = $this->initArgumentDefinition($argumentPosition);
if ($registerInstanceIfNew === true) {
$this->registerArgumentDefinition($argumentPosition, $definition);
}
return $definition;
}
public function initArgumentDefinition($argumentPosition)
{
if (is_string($argumentPosition) && isset($this->_argumentIndex[$argumentPosition])) {
$argumentPosition = $this->_argumentIndex[$argumentPosition];
}
if (!is_int($argumentPosition)) {
throw new CoreException\DependencyInjection\InvalidArgumentException('Argument could only be found by position or by name.');
}
$class = $this->getArgumentDefinitionClassName();
return new $class($this, $argumentPosition, $this->getRegistry());
}
public function registerArgumentDefinition($argumentPosition, ArgumentDefinition $argumentDefinition)
{
if (is_string($argumentPosition) && isset($this->_argumentIndex[$argumentPosition])) {
$argumentPosition = $this->_argumentIndex[$argumentPosition];
}
if (!is_int($argumentPosition)) {
throw new CoreException\DependencyInjection\InvalidArgumentException('Argument could only be found by position or by name.');
}
$this->_argumentDefinitions[$argumentPosition] = $argumentDefinition;
return $this;
}
public function addArgumentDefinition($argumentPosition)
{
$this->registerArgumentDefinition($argumentPosition, $this->initArgumentDefinition($argumentPosition));
return $this;
}
public function setArgumentDefinition($argumentPosition, ArgumentDefinition $definition)
{
if (is_string($argumentPosition) && isset($this->_argumentIndex[$argumentPosition])) {
$argumentPosition = $this->_argumentIndex[$argumentPosition];
}
if (!is_int($argumentPosition)) {
throw new CoreException\DependencyInjection\InvalidArgumentException('Argument could only be found by position or by name.');
}
$this->_argumentDefinitions[$argumentPosition] = $definition;
return $this;
}
public function setArgumentDefinitionClassName($argumentDefinitionClassName)
{
if (!is_string($argumentDefinitionClassName)) {
throw new CoreException\DependencyInjection\InvalidArgumentException('Class names only accept string.');
}
return $this->_argumentDefinitionClassName;
}
public function getArgumentDefinitionClassName()
{
return $this->_argumentDefinitionClassName;
}
/** /**
* @param string|int $argumentPosition * @param string|int $argumentPosition
* @param mixed $argumentValue * @param mixed $argumentValue
@ -108,7 +189,7 @@ class MethodDefinition
*/ */
public function bindArgumentValue($argumentPosition, $argumentValue) public function bindArgumentValue($argumentPosition, $argumentValue)
{ {
$this->getArgumentDefinition($argumentPosition)->bindValue($argumentValue); $this->getArgumentDefinition($argumentPosition, true)->bindValue($argumentValue);
return $this; return $this;
} }
@ -121,7 +202,7 @@ class MethodDefinition
*/ */
public function bindArgumentVariable($argumentPosition, &$argumentVariable) public function bindArgumentVariable($argumentPosition, &$argumentVariable)
{ {
$this->getArgumentDefinition($argumentPosition)->bindVariable($argumentVariable); $this->getArgumentDefinition($argumentPosition, true)->bindVariable($argumentVariable);
return $this; return $this;
} }
@ -139,39 +220,17 @@ class MethodDefinition
throw new CoreException\DependencyInjection\RuntimeException('No registry available'); throw new CoreException\DependencyInjection\RuntimeException('No registry available');
} }
$this->getArgumentDefinition($argumentPosition)->bindRegistryEntry($registryKey); $this->getArgumentDefinition($argumentPosition, true)->bindRegistryEntry($registryKey);
return $this; return $this;
} }
/**
* @param int|string $argumentPosition
* @return \Wootook\Core\DependencyInjection\Definition\ArgumentDefinition
* @throws \Wootook\Core\Exception\DependencyInjection\InvalidArgumentException
*/
public function getArgumentDefinition($argumentPosition)
{
if (is_string($argumentPosition) && isset($this->_argumentIndex[$argumentPosition])) {
$argumentPosition = $this->_argumentIndex[$argumentPosition];
}
if (!is_int($argumentPosition)) {
throw new CoreException\DependencyInjection\InvalidArgumentException('Argument not found.');
}
if (!isset($this->_arguments[$argumentPosition])) {
$this->_arguments[$argumentPosition] = $this->_getArgumentDefinitionInstance($argumentPosition);
}
return $this->_arguments[$argumentPosition];
}
/** /**
* @return array * @return array
*/ */
public function getAllArgumentDefinitions() public function getAllArgumentDefinitions()
{ {
return $this->_arguments; return $this->_argumentDefinitions;
} }
/** /**

View file

@ -16,11 +16,15 @@ class Factory
protected $_classDefinitionClassName = 'Wootook\\Core\\DependencyInjection\\Definition\\ClassDefinition'; protected $_classDefinitionClassName = 'Wootook\\Core\\DependencyInjection\\Definition\\ClassDefinition';
protected function _construct(Registry $registry = null) protected function _construct(Registry $registry = null, $classDefinitionClassName = null)
{ {
if ($registry !== null) { if ($registry !== null) {
$this->setRegistry($registry); $this->setRegistry($registry);
} }
if ($classDefinitionClassName !== null) {
$this->setClassDefinitionClassName($classDefinitionClassName);
}
} }
public function setRegistry(Registry $registry) public function setRegistry(Registry $registry)
@ -39,23 +43,38 @@ class Factory
return $this->_registry; return $this->_registry;
} }
public function getClassDefinition($className) public function getClassDefinition($className, $registerInstanceIfNew = false)
{ {
if (!is_string($className)) {
throw new CoreException\DependencyInjection\InvalidArgumentException('Class names only accept string.');
}
if (isset($this->_classDefinitions[$className])) { if (isset($this->_classDefinitions[$className])) {
return $this->_classDefinitions[$className]; return $this->_classDefinitions[$className];
} }
$definition = $this->initClassDefinition($className);
if ($registerInstanceIfNew === true) {
$this->registerClassDefinition($className, $definition);
}
return $definition;
return $this->initClassDefinition($className); return $this->initClassDefinition($className);
} }
public function initClassDefinition($className) public function initClassDefinition($className)
{ {
$class = $this->getClassDefinitionClassName(); $class = $this->getClassDefinitionClassName();
return new $class($className); return new $class($className);
} }
public function registerClassDefinition($className, Definition\ClassDefinition $classDefinition) public function registerClassDefinition($className, Definition\ClassDefinition $classDefinition)
{ {
if (!is_string($className)) {
throw new CoreException\DependencyInjection\InvalidArgumentException('Class names only accept string.');
}
$this->_classDefinitions[$className] = $classDefinition; $this->_classDefinitions[$className] = $classDefinition;
return $this; return $this;
@ -68,9 +87,29 @@ class Factory
return $this; return $this;
} }
public function setClassDefinitionClassName($className) public function setClassDefinition($className, Definition\ClassDefinition $definition)
{ {
$this->_classDefinitionClassName = $className; if (!is_string($className)) {
throw new CoreException\DependencyInjection\InvalidArgumentException('Class names only accept string.');
}
$this->_classDefinitions[$className] = $definition;
return $this;
}
public function getAllClassDefinitions()
{
return $this->_classDefinitions;
}
public function setClassDefinitionClassName($classDefinitionClassName)
{
if (!is_string($classDefinitionClassName)) {
throw new CoreException\DependencyInjection\InvalidArgumentException('Class names only accept string.');
}
$this->_classDefinitionClassName = $classDefinitionClassName;
return $this; return $this;
} }
@ -80,6 +119,11 @@ class Factory
return $this->_classDefinitionClassName; return $this->_classDefinitionClassName;
} }
public function reset()
{
return $this->_classDefinitions = array();
}
public function __invoke($className, Array $additionalArguments = array()) public function __invoke($className, Array $additionalArguments = array())
{ {
$definition = $this->getClassDefinition($className); $definition = $this->getClassDefinition($className);

View file

@ -0,0 +1,143 @@
<?php
namespace WootookUnit\Core\DependencyInjection\Config;
/**
* Test class for Wootook\Core\BaseObject.
* Generated by PHPUnit on 2011-09-01 at 11:24:52.
* @requires
*/
class ConfigTest extends \PHPUnit_Framework_TestCase
{
/**
* @var \Wootook\Core\App\App
*/
protected $_app;
/**
* @var \Wootook\Core\Config\Node
*/
protected $_config;
/**
* @var \Wootook\Core\DependencyInjection\Registry
*/
protected $_registry;
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*/
protected function setUp()
{
$this->_app = $this->getMock('Wootook\\Core\\App\\App', array('__construct'), array(''));
$this->_registry = new \Wootook\Core\DependencyInjection\Registry($this->_app);
}
public function testGetRegistryWhilePassedToConstructor()
{
$object = new \Wootook\Core\DependencyInjection\Factory($this->_app, $this->_registry);
$this->assertAttributeSame($this->_registry, '_registry', $object);
$this->assertSame($object->getRegistry(), $this->_registry);
}
public function testGetClassDefinition_usingSpecialClassName()
{
$object = new \Wootook\Core\DependencyInjection\Factory($this->_app, $this->_registry, 'stdClass');
$this->assertInstanceOf('stdClass', $object->getClassDefinition('stdClass'));
}
public function testGetRegistryWhileNonePassedToConstructor()
{
$object = new \Wootook\Core\DependencyInjection\Factory($this->_app);
$this->assertInstanceOf('Wootook\\Core\\DependencyInjection\\Registry', $object->getRegistry());
$this->assertAttributeNotEmpty('_registry', $object);
$this->assertAttributeNotSame($this->_registry, '_registry', $object);
$object->setRegistry($this->_registry);
$this->assertAttributeSame($this->_registry, '_registry', $object);
$this->assertSame($object->getRegistry(), $this->_registry);
}
public function testGetUndeclaredClassDefinition()
{
$object = new \Wootook\Core\DependencyInjection\Factory($this->_app, $this->_registry);
$this->assertInstanceOf('Wootook\\Core\\DependencyInjection\\Definition\\ClassDefinition', $object->getClassDefinition('stdClass'));
}
public function testGetDeclaredClassDefinition()
{
$object = new \Wootook\Core\DependencyInjection\Factory($this->_app, $this->_registry);
$classDefinition = $this->getMockBuilder('Wootook\\Core\\DependencyInjection\\Definition\\ClassDefinition')
->disableOriginalConstructor()
->getMock()
;
$object->registerClassDefinition('stdClass', $classDefinition);
$this->assertInstanceOf('Wootook\\Core\\DependencyInjection\\Definition\\ClassDefinition', $object->getClassDefinition('stdClass'));
}
public function testAddClassDefinition()
{
$classDefinition = $this->getMockBuilder('Wootook\\Core\\DependencyInjection\\Definition\\ClassDefinition')
->disableOriginalConstructor()
->getMock()
;
$object = $this->getMockBuilder('Wootook\\Core\\DependencyInjection\\Factory')
->disableOriginalConstructor()
->setMethods(array('initClassDefinition', 'registerClassDefinition'))
->getMock()
;
$object->expects($this->once())
->method('initClassDefinition')
->with('stdClass')
->will($this->returnValue($classDefinition))
;
$object->expects($this->once())
->method('registerClassDefinition')
->with('stdClass', $classDefinition)
->will($this->returnSelf())
;
$object->addClassDefinition('stdClass');
}
public function testInstanceInvocation()
{
$classDefinition = $this->getMockBuilder('Wootook\\Core\\DependencyInjection\\Definition\\ClassDefinition')
->disableOriginalConstructor()
->setMethods(array('newInstance'))
->getMock()
;
$classDefinition->expects($this->once())
->method('newInstance')
->with(array())
->will($this->returnValue(new \stdClass))
;
$object = $this->getMockBuilder('Wootook\\Core\\DependencyInjection\\Factory')
->disableOriginalConstructor()
->setMethods(array('getClassDefinition'))
->getMock()
;
$object->expects($this->once())
->method('getClassDefinition')
->with('stdClass')
->will($this->returnValue($classDefinition))
;
$object('stdClass');
}
}

View file

@ -18,7 +18,7 @@ class ClassDefinitionTest extends \PHPUnit_Framework_TestCase
$methodDefinitionClassName = \uniqid('WootookUnit_Core_DependencyInjection_Mock_MethodDefinition_TestNewInstance_'); $methodDefinitionClassName = \uniqid('WootookUnit_Core_DependencyInjection_Mock_MethodDefinition_TestNewInstance_');
$this->getMock('Wootook\\Core\\DependencyInjection\\Definition\\MethodDefinition', array(), array(), $methodDefinitionClassName, false); $this->getMock('Wootook\\Core\\DependencyInjection\\Definition\\MethodDefinition', array(), array(), $methodDefinitionClassName, false);
$definition = new Definition\ClassDefinition(__CLASS__, $methodDefinitionClassName); $definition = new Definition\ClassDefinition(__CLASS__, null, $methodDefinitionClassName);
$this->assertInstanceOf($methodDefinitionClassName, $definition->getMethodDefinition(__FUNCTION__)); $this->assertInstanceOf($methodDefinitionClassName, $definition->getMethodDefinition(__FUNCTION__));
} }

View file

@ -42,6 +42,13 @@ class FactoryTest extends \PHPUnit_Framework_TestCase
$this->assertSame($object->getRegistry(), $this->_registry); $this->assertSame($object->getRegistry(), $this->_registry);
} }
public function testGetClassDefinition_usingSpecialClassName()
{
$object = new \Wootook\Core\DependencyInjection\Factory($this->_app, $this->_registry, 'stdClass');
$this->assertInstanceOf('stdClass', $object->getClassDefinition('stdClass'));
}
public function testGetRegistryWhileNonePassedToConstructor() public function testGetRegistryWhileNonePassedToConstructor()
{ {
$object = new \Wootook\Core\DependencyInjection\Factory($this->_app); $object = new \Wootook\Core\DependencyInjection\Factory($this->_app);
@ -56,10 +63,81 @@ class FactoryTest extends \PHPUnit_Framework_TestCase
$this->assertSame($object->getRegistry(), $this->_registry); $this->assertSame($object->getRegistry(), $this->_registry);
} }
public function testGetDefinition() public function testGetUndeclaredClassDefinition()
{ {
$object = new \Wootook\Core\DependencyInjection\Factory($this->_app, $this->_registry); $object = new \Wootook\Core\DependencyInjection\Factory($this->_app, $this->_registry);
$this->assertInstanceOf('Wootook\\Core\\DependencyInjection\\Definition\\ClassDefinition', $object->getClassDefinition('stdClass')); $this->assertInstanceOf('Wootook\\Core\\DependencyInjection\\Definition\\ClassDefinition', $object->getClassDefinition('stdClass'));
} }
public function testGetDeclaredClassDefinition()
{
$object = new \Wootook\Core\DependencyInjection\Factory($this->_app, $this->_registry);
$classDefinition = $this->getMockBuilder('Wootook\\Core\\DependencyInjection\\Definition\\ClassDefinition')
->disableOriginalConstructor()
->getMock()
;
$object->registerClassDefinition('stdClass', $classDefinition);
$this->assertInstanceOf('Wootook\\Core\\DependencyInjection\\Definition\\ClassDefinition', $object->getClassDefinition('stdClass'));
}
public function testAddClassDefinition()
{
$classDefinition = $this->getMockBuilder('Wootook\\Core\\DependencyInjection\\Definition\\ClassDefinition')
->disableOriginalConstructor()
->getMock()
;
$object = $this->getMockBuilder('Wootook\\Core\\DependencyInjection\\Factory')
->disableOriginalConstructor()
->setMethods(array('initClassDefinition', 'registerClassDefinition'))
->getMock()
;
$object->expects($this->once())
->method('initClassDefinition')
->with('stdClass')
->will($this->returnValue($classDefinition))
;
$object->expects($this->once())
->method('registerClassDefinition')
->with('stdClass', $classDefinition)
->will($this->returnSelf())
;
$object->addClassDefinition('stdClass');
}
public function testInstanceInvocation()
{
$classDefinition = $this->getMockBuilder('Wootook\\Core\\DependencyInjection\\Definition\\ClassDefinition')
->disableOriginalConstructor()
->setMethods(array('newInstance'))
->getMock()
;
$classDefinition->expects($this->once())
->method('newInstance')
->with(array())
->will($this->returnValue(new \stdClass))
;
$object = $this->getMockBuilder('Wootook\\Core\\DependencyInjection\\Factory')
->disableOriginalConstructor()
->setMethods(array('getClassDefinition'))
->getMock()
;
$object->expects($this->once())
->method('getClassDefinition')
->with('stdClass')
->will($this->returnValue($classDefinition))
;
$object('stdClass');
}
} }