Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added basics for property injection

  • Loading branch information...
commit 8dca0c9f03d776e766dfb486b6f635e6d3a61132 1 parent 5f6f0c7
@rodnaph rodnaph authored
View
12 lib/BoxUK/Inject/Annotation/InjectProperty.class.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Used to annotate properties that should be injected
+ *
+ * @Target("property")
+ *
+ * @copyright Copyright (c) 2010, Box UK
+ * @license http://opensource.org/licenses/mit-license.php MIT License
+ * @link http://github.com/boxuk/boxuk-di
+ * @since 1.0
+ */
+class InjectProperty extends Annotation {}
View
62 lib/BoxUK/Inject/Standard.class.php
@@ -25,6 +25,7 @@ class Standard implements Injector {
*/
const INJECT_METHOD = 'InjectMethod';
const INJECT_PARAM = 'InjectParam';
+ const INJECT_PROPERTY = 'InjectProperty';
/**
* @var BoxUK\Reflect\Reflector
@@ -156,6 +157,7 @@ public function getNewClass( $className ) {
: new $className();
$this->injectMethods( $oClass );
+ $this->injectProperties( $oClass );
return $oClass;
@@ -276,19 +278,19 @@ protected function getParamClassFromAnnotation( $className, $methodName, $paramN
}
/**
- * Checks a classes method to find injectable ones (AInjectMethod), but won't
+ * Checks a classes method to find injectable ones (InjectMethod), but won't
* descend into ignored parent classes.
*
- * @param object $oClass
+ * @param object $class
*/
- protected function injectMethods( $oClass ) {
+ protected function injectMethods( $class ) {
- $className = get_class( $oClass );
+ $className = get_class( $class );
$methods = $this->reflector->getMethods( $className );
foreach ( $methods as $methodName ) {
if ( $this->reflector->methodHasAnnotation($className,$methodName,self::INJECT_METHOD) ) {
- $this->injectMethod( $oClass, $methodName );
+ $this->injectMethod( $class, $methodName );
}
}
@@ -297,15 +299,57 @@ protected function injectMethods( $oClass ) {
/**
* Injects a method with it's parameters
*
- * @param object $oClass
+ * @param object $class
* @param string $methodName
*/
- protected function injectMethod( $oClass, $methodName ) {
+ protected function injectMethod( $class, $methodName ) {
- $params = $this->getMethodParams( get_class($oClass), $methodName );
+ $params = $this->getMethodParams( get_class($class), $methodName );
- call_user_func_array( array($oClass,$methodName), $params );
+ call_user_func_array( array($class,$methodName), $params );
}
+ /**
+ * Do property injection on the specified class
+ *
+ * @param object $class
+ */
+ protected function injectProperties( $class ) {
+
+ $className = get_class( $class );
+ $properties = $this->reflector->getProperties( $className );
+
+ foreach ( $properties as $propertyName ) {
+ if ( $this->reflector->propertyHasAnnotation($class,$propertyName,self::INJECT_PROPERTY) ) {
+ $this->injectProperty( $class, $propertyName );
+ }
+ }
+
+ }
+
+ /**
+ * Inject the specified property of the class
+ *
+ * @param object $class
+ * @param string $propertyName
+ */
+ protected function injectProperty( $class, $propertyName ) {
+
+ $className = get_class( $class );
+ $propertyClass = $this->reflector->getPropertyClass( $className, $propertyName );
+ $propertyValue = $this->getClass( $propertyClass );
+
+ if ( $this->reflector->isPublicProperty($className,$propertyName) ) {
+ $class->$propertyName = $propertyValue;
+ }
+
+ else {
+ $property = new \ReflectionProperty( $className, $propertyName );
+ $property->setAccessible( true );
+ $property->setValue( $class, $propertyValue );
+ }
+
+ }
+
}
View
42 lib/BoxUK/Reflect/Reflector.class.php
@@ -114,4 +114,46 @@ public function getClassAnnotation( $className, $annotation );
*/
public function addIgnoredClassPattern( $regex );
+ /**
+ * Returns an array of the names of a classes private and public properties
+ *
+ * @param string $className
+ *
+ * @return array
+ */
+ public function getProperties( $className );
+
+ /**
+ * Indicates if a property has a particular annotation
+ *
+ * @param string $className
+ * @param string $propertyName
+ * @param string $annotation
+ *
+ * @return bool
+ */
+ public function propertyHasAnnotation( $className, $propertyName, $annotation );
+
+ /**
+ * Fetch the specified property class for the classes property. Returns false
+ * if nothing is found.
+ *
+ * @param string $className
+ * @param string $propertyName
+ *
+ * @return Annotation
+ */
+ public function getPropertyClass( $className, $propertyName );
+
+ /**
+ * Determines if a property is public or not. Returns true if it is public,
+ * or false if it's protected or private.
+ *
+ * @param string $className
+ * @param string $propertyName
+ *
+ * @return bool
+ */
+ public function isPublicProperty( $className, $propertyName );
+
}
View
114 lib/BoxUK/Reflect/Standard.class.php
@@ -4,9 +4,11 @@
use ReflectionClass;
use ReflectionMethod;
+use ReflectionProperty;
use ReflectionAnnotatedClass;
use ReflectionAnnotatedMethod;
+use ReflectionAnnotatedProperty;
/**
* Standard reflector implementation which provides methods for accessing
@@ -122,17 +124,13 @@ public function getMethods( $className ) {
foreach ( $class->getMethods() as $method ) {
- $className = $method->getDeclaringClass()
- ->getName();
+ $declaringClass = $method->getDeclaringClass()
+ ->getName();
- foreach ( $this->ignoredPatterns as $ignoreRegex ) {
- if ( preg_match("/$ignoreRegex/",$className) ) {
- break 2;
- }
+ if ( !$this->isIgnoredClass($declaringClass) ) {
+ $methods[] = $method->getName();
}
- $methods[] = $method->getName();
-
}
return $methods;
@@ -140,6 +138,25 @@ public function getMethods( $className ) {
}
/**
+ * Indicates if the class name matches one of the ignored patterns
+ *
+ * @param string $className
+ *
+ * @return bool
+ */
+ protected function isIgnoredClass( $className ) {
+
+ foreach ( $this->ignoredPatterns as $ignoreRegex ) {
+ if ( preg_match("/$ignoreRegex/",$className) ) {
+ return true;
+ }
+ }
+
+ return false;
+
+ }
+
+ /**
* Indicates if a class has the specified annotation
*
* @param string $className
@@ -222,4 +239,85 @@ public function getClassAnnotation( $className, $annotation ) {
}
+ /**
+ * Returns an array of the names of a classes properties (public and private)
+ *
+ * @param string $className
+ *
+ * @return array
+ */
+ public function getProperties( $className ) {
+
+ $class = new ReflectionClass( $className );
+ $properties = array();
+
+ foreach ( $class->getProperties() as $property ) {
+
+ $declaringClass = $property->getDeclaringClass()
+ ->getName();
+
+ if ( !$this->isIgnoredClass($declaringClass) ) {
+ $properties[] = $property->getName();
+ }
+
+ }
+
+ return $properties;
+
+ }
+
+ /**
+ * Indicates if a classes property has the specified annotation
+ *
+ * @param string $className
+ * @param string $propertyName
+ * @param string $annotation
+ *
+ * @return bool
+ */
+ public function propertyHasAnnotation( $className, $propertyName, $annotation ) {
+
+ $property = new ReflectionAnnotatedProperty( $className, $propertyName );
+
+ return $property->hasAnnotation( $annotation );
+
+ }
+
+ /**
+ * Returns the declared class for a classes property (eg. @var SomeClass)
+ *
+ * @param string $className
+ * @param string $propertyName
+ *
+ * @return string
+ */
+ public function getPropertyClass( $className, $propertyName ) {
+
+ $property = new ReflectionProperty( $className, $propertyName );
+ $comment = $property->getDocComment();
+
+ if ( preg_match('/@var ([\w\\\\]+)/i',$comment,$matches) ) {
+ return $matches[ 1 ];
+ }
+
+ return false;
+
+ }
+
+ /**
+ * Indicates if a given class property is public
+ *
+ * @param string $className
+ * @param string $propertyName
+ *
+ * @return bool
+ */
+ public function isPublicProperty( $className, $propertyName ) {
+
+ $property = new ReflectionProperty( $className, $propertyName );
+
+ return $property->isPublic();
+
+ }
+
}
View
1  lib/bootstrap.php
@@ -2,6 +2,7 @@
require 'BoxUK/Inject/Annotation/InjectMethod.class.php';
require 'BoxUK/Inject/Annotation/InjectParam.class.php';
+require 'BoxUK/Inject/Annotation/InjectProperty.class.php';
require 'BoxUK/Inject/Annotation/ScopeSingleton.class.php';
require 'BoxUK/Inject/Annotation/ScopeSession.class.php';
View
28 tests/php/BoxUK/Inject/StandardTest.php
@@ -150,6 +150,18 @@ public function testInjectParamsAreIgnoredWhenTheyDontMatchParameters() {
$class = $inject->getClass( 'BoxUK\Inject\StandardInjectorTest_TestClass11' );
}
+ public function testPropertiesWithInjectPropertyAnnotationAreInjectorByVarType() {
+ $inject = $this->getInstance();
+ $class = $inject->getClass( 'BoxUK\Inject\StandardInjectorTest_TestClass7' );
+ $this->assertInstanceOf( 'BoxUK\Inject\StandardInjectorTest_TestClass3', $class->publicProperty );
+ }
+
+ public function testPrivatePropertiesCanBeInjected() {
+ $inject = $this->getInstance();
+ $class = $inject->getClass( 'BoxUK\Inject\StandardInjectorTest_TestClass7' );
+ $this->assertInstanceOf( 'BoxUK\Inject\StandardInjectorTest_TestClass3', $class->getPrivateProperty() );
+ }
+
}
class StandardInjectorTest_TestClass {}
@@ -196,6 +208,22 @@ class StandardInjectorTest_TestClass6 implements StandardInjectorTest_TestInterf
class StandardInjectorTest_TestClass7 {
public $oObject = null;
+
+ /**
+ * @InjectProperty
+ * @var BoxUK\Inject\StandardInjectorTest_TestClass3
+ */
+ public $publicProperty;
+
+ /**
+ * @InjectProperty
+ * @var BoxUK\Inject\StandardInjectorTest_TestClass3
+ */
+ private $privateProperty;
+
+ public function getPrivateProperty() {
+ return $this->privateProperty;
+ }
/**
* @InjectMethod
View
74 tests/php/BoxUK/Reflect/StandardTest.php
@@ -81,9 +81,74 @@ public function testGettingAMethodAnnotationReturnsIt() {
$this->assertInstanceOf( 'InjectMethod', $annotation );
}
+ public function testPropertiesReturnedByGetClassProperties() {
+ $properties = $this->reflector->getProperties( 'BoxUK\Reflect\SimpleReflectorTest_Class1' );
+ $this->assertEquals( 4, count($properties) );
+ }
+
+ public function testGetClassPropertiesReturnsPrivateProperties() {
+ $properties = $this->reflector->getProperties( 'BoxUK\Reflect\SimpleReflectorTest_Class1' );
+ $this->assertTrue( in_array('private',$properties) );
+ }
+
+ public function testGetClassPropertiesReturnsProtectedProperties() {
+ $properties = $this->reflector->getProperties( 'BoxUK\Reflect\SimpleReflectorTest_Class1' );
+ $this->assertTrue( in_array('protected',$properties) );
+ }
+
+ public function testPropertyHasAnnotationReturnsTrueWhenThePropertyHasTheAnnotation() {
+ $this->assertTrue( $this->reflector->propertyHasAnnotation('BoxUK\Reflect\SimpleReflectorTest_Class1','public','InjectProperty') );
+ }
+
+ public function testPropertyHasAnnotationReturnsFalseWhenThePropertyDoesntHaveTheAnnotation() {
+ $this->assertFalse( $this->reflector->propertyHasAnnotation('BoxUK\Reflect\SimpleReflectorTest_Class1','another','InjectProperty') );
+ }
+
+ public function testAtVarClassNameReturnedForClassProperty() {
+ $this->assertEquals( 'ChildClass', $this->reflector->getPropertyClass('BoxUK\Reflect\SimpleReflectorTest_Class1','public') );
+ }
+
+ public function testGettingAPropertiesClassCanHandleNamespaces() {
+ $this->assertEquals( 'BoxUK\Reflect\SimpleReflectorTest_Class2', $this->reflector->getPropertyClass('BoxUK\Reflect\ChildClass','someProperty') );
+ }
+
+ public function testFalseReturnedWhenClassPropertyDoesntHaveAnAtVar() {
+ $this->assertFalse( $this->reflector->getPropertyClass('BoxUK\Reflect\SimpleReflectorTest_Class1','another') );
+ }
+
+ public function testGetpropertiesDoesntReturnPropertiesFromIgnoredClasses() {
+ $this->reflector->addIgnoredClassPattern( 'Doctrine_.*' );
+ $properties = $this->reflector->getProperties( 'BoxUK\Reflect\ChildClass' );
+ $this->assertFalse( in_array('ignoreMe',$properties) );
+ }
+
+ public function testIspublicpropertyReturnsTrueWhenPropertyIsPublic() {
+ $this->assertTrue( $this->reflector->isPublicProperty('BoxUK\Reflect\SimpleReflectorTest_Class1','public') );
+ }
+
+ public function testIspublicpropertyReturnsFalseWhenPropertyIsProtected() {
+ $this->assertFalse( $this->reflector->isPublicProperty('BoxUK\Reflect\SimpleReflectorTest_Class1','protected') );
+ }
+
+ public function testIspublicpropertyReturnsFalseWhenPropertyIsPrivate() {
+ $this->assertFalse( $this->reflector->isPublicProperty('BoxUK\Reflect\SimpleReflectorTest_Class1','private') );
+ }
+
}
class SimpleReflectorTest_Class1 {
+ /**
+ * @InjectProperty
+ * @var ChildClass
+ */
+ public $public;
+ public $another;
+ protected $protected;
+ /**
+ * @InjectProperty
+ * @var ChildClass
+ */
+ private $private;
public function foo() {}
/**
* @InjectParam(variable=oClass1)
@@ -101,10 +166,17 @@ public function subfoo() {}
}
class Doctrine_Class {
+ public $ignoreMe;
/**
* @InjectMethod
*/
public function docFoo() {}
}
-class ChildClass extends Doctrine_Class {}
+class ChildClass extends Doctrine_Class {
+ /**
+ * @InjectProperty
+ * @var BoxUK\Reflect\SimpleReflectorTest_Class2
+ */
+ public $someProperty;
+}
Please sign in to comment.
Something went wrong with that request. Please try again.