Skip to content

Commit

Permalink
Merge pull request #17 from koriym/refactor-2
Browse files Browse the repository at this point in the history
Extract classes to refactor
  • Loading branch information
koriym committed May 21, 2015
2 parents b8fd746 + 525a021 commit f9b7733
Show file tree
Hide file tree
Showing 12 changed files with 276 additions and 183 deletions.
73 changes: 73 additions & 0 deletions src/AopCode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php
/**
* This file is part of the Ray.Compiler package.
*
* @license http://opensource.org/licenses/bsd-license.php MIT
*/
namespace Ray\Compiler;

use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar;
use Ray\Aop\Interceptor;
use Ray\Di\Dependency;
use Ray\Di\Name;

final class AopCode
{
/**
* @var PrivateProperty
*/
private $privateProperty;

public function __construct(PrivateProperty $privateProperty)
{
$this->privateProperty = $privateProperty;
}

/**
* Add aop factory code if bindings are given
*
* @param Dependency $dependency
* @param array $node
*/
public function __invoke(Dependency $dependency, array &$node)
{
$prop = $this->privateProperty;
$newInstance = $prop($dependency, 'newInstance');
$bind = $prop($newInstance, 'bind');
$bind = $prop($bind, 'bind');
/** @var array $bindings */
$bindings = $prop($bind, 'bindings', null);
if (! $bindings || ! is_array($bindings)) {
return;
}
$methodBinding = $this->getMethodBinding($bindings);
$bindingsProp = new Expr\PropertyFetch(new Expr\Variable('instance'), 'bindings');
$node[] = new Expr\Assign($bindingsProp, new Expr\Array_($methodBinding));
}

/**
* @param Interceptor[] $bindings
*
* @return Expr\ArrayItem[]
*/
private function getMethodBinding($bindings)
{
$methodBinding = [];
foreach ($bindings as $method => $interceptors) {
$items = [];
foreach ($interceptors as $interceptor) {
// $singleton('FakeAopInterface-*');
$dependencyIndex = "{$interceptor}-" . Name::ANY;
$singleton = new Expr\FuncCall(new Expr\Variable('singleton'), [new Node\Arg(new Scalar\String_($dependencyIndex))]);
// [$singleton('FakeAopInterface-*'), $singleton('FakeAopInterface-*');]
$items[] = new Expr\ArrayItem($singleton);
}
$arr = new Expr\Array_($items);
$methodBinding[] = new Expr\ArrayItem($arr, new Scalar\String_($method));
}

return $methodBinding;
}
}
3 changes: 2 additions & 1 deletion src/Code.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
namespace Ray\Compiler;

use PhpParser\PrettyPrinter\Standard;
use PhpParser\Node;

final class Code
Expand All @@ -32,7 +33,7 @@ public function __construct(Node $node, $isSingleton = false)

public function __toString()
{
$prettyPrinter = new \PhpParser\PrettyPrinter\Standard();
$prettyPrinter = new Standard();
$classCode = $prettyPrinter->prettyPrintFile([$this->node]);

return $classCode;
Expand Down
170 changes: 28 additions & 142 deletions src/DependencyCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@
*/
namespace Ray\Compiler;

use PhpParser\BuilderFactory;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt;
use Ray\Aop\Interceptor;
use Ray\Di\Argument;
use Ray\Di\Container;
use Ray\Di\Dependency;
use Ray\Di\DependencyInterface;
use Ray\Di\DependencyProvider;
use Ray\Di\Instance;
use Ray\Di\Name;

final class DependencyCompiler
{
Expand Down Expand Up @@ -46,13 +44,25 @@ final class DependencyCompiler
*/
private $factoryCompiler;

/**
* @var PrivateProperty
*/
private $privateProperty;

/**
* @var AopCode
*/
private $aopCode;

public function __construct(Container $container, ScriptInjector $injector = null)
{
$this->factory = new \PhpParser\BuilderFactory;
$this->factory = new BuilderFactory;
$this->container = $container;
$this->normalizer = new Normalizer;
$this->injector = $injector;
$this->factoryCompiler = new FactoryCompiler($container, new Normalizer, $this, $injector);
$this->privateProperty = new PrivateProperty;
$this->aopCode = new AopCode($this->privateProperty);
}

/**
Expand All @@ -75,25 +85,6 @@ public function compile(DependencyInterface $dependency)
throw new \DomainException(get_class($dependency));
}

/**
* Return arguments code for "$singleton" and "$prototype"
*
* @param Argument $argument
* @param DependencyInterface $dependency
*
* @return Expr\FuncCall
*/
public function getPullDependency(Argument $argument, DependencyInterface $dependency)
{
$isSingleton = $this->getPrivateProperty($dependency, 'isSingleton');
$func = $isSingleton ? 'singleton' : 'prototype';
$args = $this->getInjectionFuncParams($argument);

$node = new Expr\FuncCall(new Expr\Variable($func), $args);

return $node;
}

/**
* Compile DependencyInstance
*
Expand All @@ -103,7 +94,7 @@ public function getPullDependency(Argument $argument, DependencyInterface $depen
*/
private function compileInstance(Instance $instance)
{
$node = $this->normalizer->normalizeValue($instance->value);
$node = $this->normalizer->__invoke($instance->value);

return new Code(new Node\Stmt\Return_($node), false);
}
Expand All @@ -117,11 +108,12 @@ private function compileInstance(Instance $instance)
*/
private function compileDependency(Dependency $dependency)
{
$prop = $this->privateProperty;
$node = $this->getFactoryNode($dependency);
$this->getAopCode($dependency, $node);
$this->aopCode->__invoke($dependency, $node);
$node[] = new Node\Stmt\Return_(new Node\Expr\Variable('instance'));
$node = $this->factory->namespace('Ray\Di\Compiler')->addStmts($node)->getNode();
$isSingleton = $this->getPrivateProperty($dependency, 'isSingleton');
$isSingleton = $prop($dependency, 'isSingleton');

return new Code($node, $isSingleton);
}
Expand All @@ -135,11 +127,12 @@ private function compileDependency(Dependency $dependency)
*/
private function compileDependencyProvider(DependencyProvider $provider)
{
$dependency = $this->getPrivateProperty($provider, 'dependency');
$prop = $this->privateProperty;
$dependency = $prop($provider, 'dependency');
$node = $this->getFactoryNode($dependency);
$node[] = new Stmt\Return_(new Expr\MethodCall(new Expr\Variable('instance'), 'get'));
$node = $this->factory->namespace('Ray\Di\Compiler')->addStmts($node)->getNode();
$isSingleton = $this->getPrivateProperty($provider, 'isSingleton');
$isSingleton = $prop($provider, 'isSingleton');

return new Code($node, $isSingleton);
}
Expand All @@ -155,121 +148,14 @@ private function compileDependencyProvider(DependencyProvider $provider)
*/
private function getFactoryNode(DependencyInterface $dependency)
{
$newInstance = $this->getPrivateProperty($dependency, 'newInstance');
$prop = $this->privateProperty;
$newInstance = $prop($dependency, 'newInstance');
// class name
$class = $this->getPrivateProperty($newInstance, 'class');
$setterMethods = (array) $this->getPrivateProperty($this->getPrivateProperty($newInstance, 'setterMethods'), 'setterMethods');
$arguments = (array) $this->getPrivateProperty($this->getPrivateProperty($newInstance, 'arguments'), 'arguments');
$postConstruct = $this->getPrivateProperty($dependency, 'postConstruct');
$isSingleton = $this->getPrivateProperty($dependency, 'isSingleton');

return $this->factoryCompiler->getFactoryCode($class, $arguments, $setterMethods, $postConstruct, $isSingleton);
}

/**
* Add aop factory code if bindings are given
*
* @param Dependency $dependency
* @param array $node
*/
private function getAopCode(Dependency $dependency, array &$node)
{
$newInstance = $this->getPrivateProperty($dependency, 'newInstance');
$bind = $this->getPrivateProperty($newInstance, 'bind');
$bind = $this->getPrivateProperty($bind, 'bind');
/** @var array $bindings */
$bindings = $this->getPrivateProperty($bind, 'bindings', null);
if (! $bindings || ! is_array($bindings)) {
return;
}
$methodBinding = $this->getMethodBinding($bindings);
$bindingsProp = new Expr\PropertyFetch(new Expr\Variable('instance'), 'bindings');
$node[] = new Expr\Assign($bindingsProp, new Expr\Array_($methodBinding));
}

/**
* Return dependency index argument
*
* [class, method, param] is added if dependency is provider for DI context
*
* @param Argument $argument
*
* @return array
*/
private function getInjectionFuncParams(Argument $argument)
{
$dependencyIndex = (string) $argument;
if ($this->container->getContainer()[$dependencyIndex] instanceof DependencyProvider) {
return $this->getInjectionProviderParams($argument);
}

return [new Node\Arg(new Scalar\String_((string) $argument))];
}

/**
* Return code for provider
*
* "$provider" needs [class, method, parameter] for InjectionPoint (Contextual Dependency Injection)
*
* @param Argument $argument
*
* @return array
*/
private function getInjectionProviderParams(Argument $argument)
{
$param = $argument->get();

return [
new Node\Arg(new Scalar\String_((string) $argument)),
new Expr\Array_([
new Node\Arg(new Scalar\String_($param->getDeclaringClass()->name)),
new Node\Arg(new Scalar\String_($param->getDeclaringFunction()->name)),
new Node\Arg(new Scalar\String_($param->name))
])
];
}

/**
* @param object $object
* @param string $prop
* @param mixed $default
*
* @return mixed|null
*/
private function getPrivateProperty($object, $prop, $default = null)
{
try {
$refProp = (new \ReflectionProperty($object, $prop));
} catch (\Exception $e) {
return $default;
}
$refProp->setAccessible(true);
$value = $refProp->getValue($object);

return $value;
}

/**
* @param Interceptor[] $bindings
*
* @return Expr\ArrayItem[]
*/
private function getMethodBinding($bindings)
{
$methodBinding = [];
foreach ($bindings as $method => $interceptors) {
$items = [];
foreach ($interceptors as $interceptor) {
// $singleton('FakeAopInterface-*');
$dependencyIndex = "{$interceptor}-" . Name::ANY;
$singleton = new Expr\FuncCall(new Expr\Variable('singleton'), [new Node\Arg(new Scalar\String_($dependencyIndex))]);
// [$singleton('FakeAopInterface-*'), $singleton('FakeAopInterface-*');]
$items[] = new Expr\ArrayItem($singleton);
}
$arr = new Expr\Array_($items);
$methodBinding[] = new Expr\ArrayItem($arr, new Scalar\String_($method));
}
$class = $prop($newInstance, 'class');
$setterMethods = (array) $prop($prop($newInstance, 'setterMethods'), 'setterMethods');
$arguments = (array) $prop($prop($newInstance, 'arguments'), 'arguments');
$postConstruct = $prop($dependency, 'postConstruct');

return $methodBinding;
return $this->factoryCompiler->getFactoryCode($class, $arguments, $setterMethods, $postConstruct);
}
}
2 changes: 1 addition & 1 deletion src/DependencySaver.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/
namespace Ray\Compiler;

class DependencySaver
final class DependencySaver
{
private $scriptDir;

Expand Down
5 changes: 5 additions & 0 deletions src/DiCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ final class DiCompiler implements InjectorInterface
*/
private $module;

/**
* @var DependencySaver
*/
private $dependencySaver;

/**
* @param AbstractModule $module
* @param string $scriptDir
Expand Down
Loading

0 comments on commit f9b7733

Please sign in to comment.