Permalink
Browse files

added basics for property injection

  • Loading branch information...
1 parent 5f6f0c7 commit 8dca0c9f03d776e766dfb486b6f635e6d3a61132 @rodnaph rodnaph committed Nov 14, 2010
@@ -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 {}
@@ -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 );
+ }
+
+ }
+
}
@@ -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 );
+
}
@@ -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,24 +124,39 @@ 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;
}
/**
+ * 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
@@ -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';
@@ -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
Oops, something went wrong.

0 comments on commit 8dca0c9

Please sign in to comment.