Skip to content

Commit

Permalink
Different inject by one interface using annotation. Part 2.
Browse files Browse the repository at this point in the history
  • Loading branch information
NasyrovYuri committed Apr 1, 2016
1 parent b935167 commit 86c7800
Show file tree
Hide file tree
Showing 8 changed files with 278 additions and 78 deletions.
54 changes: 53 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,56 @@
Inject::bindByArray(["TestInterface" => "Test", "FirstClassInterface" => "FirstClass"]);

$class = Inject::instantiation("FirstClassInterface");
var_dump($class instanceof FirstClass); // must return true
var_dump($class instanceof FirstClass); // must return true

### Different classes to one interface via DocComment
<?php
require_once __DIR__ . "/vendor/autoload.php";

interface SomeInterface
{

}

class First implements SomeInterface
{

}

class Second implements SomeInterface
{

}

class A
{
/**
* @thisAnnotationForSecondClass
* @var SomeInterface
*/
public $secondVariable;

protected $firstVariable;

/**
* A constructor.
* @thisAnnotatnionForFristClass
* @param SomeInterface $my
*/
public function __construct(SomeInterface $my)
{
$this->firstVariable = $my;
}

public function getFirst()
{
return $this->firstVariable;
}
}

use \Sixx\DependencyInjection\Inject;
Inject::bindByArray(["SomeInterface" => ["thisAnnotatnionForFristClass" => "First", "thisAnnotationForSecondClass" => "Second"]]);

$class = Inject::instantiation("A");
var_dump($class->secondVariable instanceof Second); // must return true
var_dump($class->getFirst() instanceof First); // must return true
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.0.1
0.0.2
95 changes: 22 additions & 73 deletions src/Inject.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ class Inject
protected static $services = [];
protected static $injectAnnotation = '@var';

/**
* @var ServiceContainer
*/
protected static $serviceContainer;

/**
* @param string $className
* @param array $parameters
Expand All @@ -20,8 +25,8 @@ public static function instantiation($className, array $parameters = null)
if (! class_exists($className)) {

if (interface_exists($className)) {
if (self::injectedParameter(new \ReflectionClass($className)))
return self::instantiation(self::getServiceName($className), $parameters);
if (self::container()->isInjected($className))
return self::instantiation(self::container()->getServiceName($className), $parameters);

throw new InjectException("Inject error: interface " . $className . " exist but not injected yet.");
}
Expand Down Expand Up @@ -54,8 +59,8 @@ public static function method($className, $methodName, array $parameters = null)
if (! class_exists($className)) {

if (interface_exists($className)) {
if (self::injectedParameter(new \ReflectionClass($className)))
return self::method(self::getServiceName($className), $methodName, $parameters);
if (self::container()->isInjected($className))
return self::method(self::container()->getServiceName($className), $methodName, $parameters);

throw new InjectException("Inject error: interface " . $className . " exist but not injected yet.");
}
Expand Down Expand Up @@ -86,9 +91,9 @@ protected static function getParameters(\ReflectionMethod $method, array $parame
foreach ($method->getParameters() as $parameter) {
if (isset($parameters[$parameter->getName()]))
$arguments[$parameter->getName()] = $parameters[$parameter->getName()];
elseif (self::injectedParameter($parameter->getClass()))
$arguments[$parameter->getName()] = self::instantiation(self::getServiceName($parameter->getClass()->name));
elseif (self::instantiatedParameter($parameter->getClass()))
elseif (null != $parameter->getClass() && self::container()->isInjected($parameter->getClass()->name, $method->getDocComment()))
$arguments[$parameter->getName()] = self::instantiation(self::container()->getServiceName($parameter->getClass()->name, $method->getDocComment()));
elseif (self::container()->isInstantiate($parameter->getClass()))
$arguments[$parameter->getName()] = self::instantiation($parameter->getClass()->name);
elseif (true != $parameter->isOptional())
throw new InjectException("Required parameter [" . $parameter->getName() . "] in " . $method->getDeclaringClass()->name . "::" . $method->getName() . " is not specified.");
Expand All @@ -100,33 +105,6 @@ protected static function getParameters(\ReflectionMethod $method, array $parame
return $arguments;
}

/**
* @param \ReflectionClass|null $class
* @return bool
*/
protected static function injectedParameter(\ReflectionClass $class = null)
{
if (null == $class || null == self::getServiceName($class->name))
return false;

if (false == (new \ReflectionClass(self::getServiceName($class->name)))->implementsInterface($class->name))
throw new InjectException("Inject error: class " . self::getServiceName($class->name) . " must implement " . $class->name);

return true;
}

/**
* @param \ReflectionClass|null $class
* @return bool
*/
protected static function instantiatedParameter(\ReflectionClass $class = null)
{
if (null == $class || $class->isAbstract() || $class->isInterface())
return false;

return true;
}

/**
* @param object $class
* @param array|null $properties
Expand All @@ -142,10 +120,9 @@ protected static function fillProperties($class, array $properties = null)
$className = self::getVariableTypeName($property->getDocComment(), self::$injectAnnotation);

if (class_exists($className) || interface_exists($className)) {
$propertyClass = new \ReflectionClass($className);
if (self::injectedParameter($propertyClass))
$class->$name = self::instantiation(self::getServiceName($className));
elseif (self::instantiatedParameter($propertyClass))
if (self::container()->isInjected($className, $property->getDocComment()))
$class->$name = self::instantiation(self::container()->getServiceName($className, $property->getDocComment()));
elseif (self::container()->isInstantiate(new \ReflectionClass($className)))
$class->$name = self::instantiation($className);
}
}
Expand All @@ -168,32 +145,22 @@ protected static function getVariableTypeName($string, $injectAnnotation)
}

/**
* @param string $serviceName
* @param string $annotation
* @return null|string
* @return ServiceContainer
*/
protected static function getServiceName($serviceName, $annotation = "")
protected static function container()
{
if (isset(self::$services[$serviceName])) {
if (is_string(self::$services[$serviceName]))
return self::$services[$serviceName];
elseif (is_array(self::$services[$serviceName])) {
foreach (self::$services[$serviceName] as $name => $service) {
if (false !== strpos($annotation, "@" . $name))
return $service;
}
}
}
if (empty(self::$serviceContainer))
self::$serviceContainer = new ServiceContainer();

return null;
return self::$serviceContainer;
}

/**
* Flush all services from Inject
*/
public static function flushServices()
{
self::$services = [];
self::container()->flushServices();
}

/**
Expand All @@ -203,25 +170,7 @@ public static function flushServices()
*/
public static function bind($interface, $class)
{
if (false == is_string($interface) || false == (is_string($class) || is_array($class)))
return false;

if (is_string($class))
self::$services[$interface] = $class;
else {
$classes = [];
foreach ($class as $name => $value) {
if (is_string($name) && is_string($value))
$classes[$name] = $value;
}

if (0 == count($classes))
return false;

self::$services[$interface] = $classes;
}

return true;
return self::container()->bind($interface, $class);
}

/**
Expand Down
114 changes: 114 additions & 0 deletions src/ServiceContainer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

namespace Sixx\DependencyInjection;

use Sixx\DependencyInjection\Exceptions\InjectException;

class ServiceContainer
{
protected $services = [];

/**
* @param string $serviceName
* @param string $annotation
* @return null|string
*/
public function getServiceName($serviceName, $annotation = "")
{
if (isset($this->services[$serviceName])) {
if (is_string($this->services[$serviceName]))
return $this->services[$serviceName];
elseif (is_array($this->services[$serviceName]) && 0 < count($this->services[$serviceName])) {
reset($this->services[$serviceName]);

if (false == is_string($annotation) || empty($annotation))
return current($this->services[$serviceName]);

foreach ($this->services[$serviceName] as $name => $service) {
if (false !== strpos($annotation, "@" . $name))
return $service;

}

reset($this->services[$serviceName]);
return current($this->services[$serviceName]);
}
}

return null;
}

/**
* Flush all services from ServiceContainer
*/
public function flushServices()
{
$this->services = [];
}

/**
* @param string $interface
* @param string|array $class
* @return bool
*/
public function bind($interface, $class)
{
if (false == (is_string($interface) && ! empty($interface)) || false == (is_string($class) && ! empty($class) || is_array($class)))
return false;

if (is_string($class))
$this->services[$interface] = $class;
else {
$classes = [];
foreach ($class as $name => $value) {
if (is_string($name) && ! empty($name) && is_string($value) && ! empty($value))
$classes[$name] = $value;
}

if (0 == count($classes))
return false;

$this->services[$interface] = $classes;
}

return true;
}

/**
* @param null|string $name
* @param null|string $annotation
* @return bool
*/
public function isInjected($name = null, $annotation = null)
{
if (null == $name || null == $this->getServiceName($name))
return false;

if (false == $this->isImplement($this->getServiceName($name, $annotation), $name))
throw new InjectException("Inject error: class " . $this->getServiceName($name, $annotation) . " must implement " . $name);

return true;
}

/**
* @param string $className
* @param string $interfaceName
* @return bool
*/
protected function isImplement($className, $interfaceName)
{
return (new \ReflectionClass($className))->implementsInterface($interfaceName);
}

/**
* @param \ReflectionClass|null $class
* @return bool
*/
public function isInstantiate(\ReflectionClass $class = null)
{
if (null == $class || $class->isAbstract() || $class->isInterface())
return false;

return true;
}
}
13 changes: 13 additions & 0 deletions tests/InjectExceptionTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use \Sixx\DependencyInjection\Inject;
use \Sixx\DependencyInjection\ServiceContainer;

class InjectExceptionTest extends PHPUnit_Framework_TestCase
{
Expand Down Expand Up @@ -55,4 +56,16 @@ public function testExceptionRequiredParameter()
Inject::bind("INext", "Next");
Inject::method("ChildClass", "hello", ["c" => "wer"]);
}

/**
* @expectedException \Sixx\DependencyInjection\Exceptions\InjectException
* @expectedExceptionMessage Inject error: class Start must implement INext
*/
public function testExceptionClassMustImplements()
{
$class = new ServiceContainer();

$class->bind("INext", "Start");
$class->isInjected("INext");
}
}
8 changes: 5 additions & 3 deletions tests/InjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class InjectTest extends PHPUnit_Framework_TestCase
public function setUp()
{
require_once __DIR__ . "/TestClasses/Classes.php";
Inject::bindByArray(["IStart" => "Start", "INext" => "Next"]);
Inject::bindByArray(["IStart" => ["star" => "Start", "second" => "Starter"], "INext" => "Next"]);
}

public function testInstantiation()
Expand All @@ -17,14 +17,16 @@ public function testInstantiation()

public function testMethod()
{
$this->assertInstanceOf("Start", Inject::method("INext", "tryMe"));
$this->assertInstanceOf("Starter", Inject::method("INext", "tryMe"));
}

public function testCheckAllInInjected()
{
$class = Inject::method("ChildClass", "hello", ["c" => "fff"]);
$this->assertInstanceOf("Next", $class->getNext());
$this->assertInstanceOf("Start", $class->getStart());
$this->assertInstanceOf("Start", $class->getNext()->tryMe());
$this->assertInstanceOf("Starter", $class->getNext()->tryMe());
$this->assertInstanceOf("Starter", Inject::method("ChildClass", "getStarter", ["c" => "fff"]));
$this->assertInstanceOf("Starter", $class->starter);
}
}
Loading

0 comments on commit 86c7800

Please sign in to comment.