diff --git a/src/Hal/Component/OOP/Extractor/ClassExtractor.php b/src/Hal/Component/OOP/Extractor/ClassExtractor.php index 20e483bd..dc683eee 100644 --- a/src/Hal/Component/OOP/Extractor/ClassExtractor.php +++ b/src/Hal/Component/OOP/Extractor/ClassExtractor.php @@ -51,7 +51,7 @@ public function extract(&$n, TokenCollection $tokens) $isAbstract = $prev && T_ABSTRACT === $prev->getType(); $classname = $this->searcher->getFollowingName($n, $tokens); - $class = new ReflectedClass($this->namespace, $classname); + $class = new ReflectedClass($this->namespace, trim($classname)); $class->setAbstract($isAbstract); return $class; } diff --git a/src/Hal/Component/OOP/Extractor/Extractor.php b/src/Hal/Component/OOP/Extractor/Extractor.php index 77fd4445..c72b26ca 100644 --- a/src/Hal/Component/OOP/Extractor/Extractor.php +++ b/src/Hal/Component/OOP/Extractor/Extractor.php @@ -8,6 +8,7 @@ */ namespace Hal\Component\OOP\Extractor; +use Hal\Component\OOP\Resolver\NameResolver; use Hal\Component\Token\Tokenizer; @@ -69,10 +70,11 @@ public function extract($filename) $result = new Result; $tokens = $this->tokenizer->tokenize($filename); + $nameResolver = new NameResolver(); // default current values $class = $interface = $function = $method = null; - $mapOfAliases = array(); +// $mapOfAliases = array(); $len = sizeof($tokens, COUNT_NORMAL); for($n = 0; $n < $len; $n++) { @@ -84,10 +86,7 @@ public function extract($filename) case T_USE: $alias = $this->extractors->alias->extract($n, $tokens); if (null !== $alias->name && null !== $alias->alias) { - $mapOfAliases[$alias->alias] = $alias->name; - $class && $class->setAliases($mapOfAliases); - $method && $method->setAliases($mapOfAliases); - $interface && $interface->setAliases($mapOfAliases); + $nameResolver->pushAlias($alias); } break; @@ -98,15 +97,21 @@ public function extract($filename) case T_INTERFACE: $class = $this->extractors->interface->extract($n, $tokens); - $class->setAliases($mapOfAliases); + $class->setNameResolver($nameResolver); // push class AND in global AND in local class map $this->result->pushClass($class); $result->pushClass($class); break; + case T_EXTENDS: + $i = $n; + $parent = $this->searcher->getFollowingName($i, $tokens); + $class->setParent(trim($parent)); + break; + case T_CLASS: $class = $this->extractors->class->extract($n, $tokens); - $class->setAliases($mapOfAliases); + $class->setNameResolver($nameResolver); // push class AND in global AND in local class map $this->result->pushClass($class); $result->pushClass($class); @@ -120,7 +125,8 @@ public function extract($filename) continue; } $method = $this->extractors->method->extract($n, $tokens); - $method->setAliases($mapOfAliases); +// $method->setAliases($mapOfAliases); + $method->setNameResolver($nameResolver); $class->pushMethod($method); } break; diff --git a/src/Hal/Component/OOP/Extractor/InterfaceExtractor.php b/src/Hal/Component/OOP/Extractor/InterfaceExtractor.php index d3881ea0..3b75522b 100644 --- a/src/Hal/Component/OOP/Extractor/InterfaceExtractor.php +++ b/src/Hal/Component/OOP/Extractor/InterfaceExtractor.php @@ -47,7 +47,7 @@ public function __construct(Searcher $searcher) public function extract(&$n, TokenCollection $tokens) { $classname = $this->searcher->getFollowingName($n, $tokens); - return new ReflectedInterface($this->namespace, $classname); + return new ReflectedInterface($this->namespace, trim($classname)); } /** diff --git a/src/Hal/Component/OOP/Reflected/ReflectedClass.php b/src/Hal/Component/OOP/Reflected/ReflectedClass.php index 9f281be0..dad95a33 100644 --- a/src/Hal/Component/OOP/Reflected/ReflectedClass.php +++ b/src/Hal/Component/OOP/Reflected/ReflectedClass.php @@ -8,6 +8,7 @@ */ namespace Hal\Component\OOP\Reflected; +use Hal\Component\OOP\Resolver\NameResolver; /** @@ -35,11 +36,11 @@ class ReflectedClass { private $methods; /** - * Map of aliases + * Resolver for names * - * @var array + * @var NameResolver */ - private $aliases = array(); + private $nameResolver; /** * Does the class is abstract ? @@ -48,6 +49,13 @@ class ReflectedClass { */ private $isAbstract = false; + /** + * Parent's name + * + * @var string + */ + private $parent; + /** * Constructor * @@ -59,6 +67,7 @@ public function __construct($namespace, $name) $this->name = (string) $name; $this->namespace = (string) $namespace; $this->methods = array(); + $this->nameResolver = new NameResolver(); } /** @@ -103,15 +112,6 @@ public function getMethods() */ public function pushMethod(ReflectedMethod $method) { $this->methods[$method->getName()] = $method; - -// foreach($method->getArguments() as $argument) { -// -// $name = $argument->getType(); -// if(!in_array($argument->getType(), array(null, $this->getName(), 'array'))) { -// $this->pushDependency($name); -// } -// } - return $this; } @@ -124,15 +124,20 @@ public function getDependencies() foreach($this->getMethods() as $method) { $dependencies = array_merge($dependencies, $method->getDependencies()); } - return $dependencies; + foreach($dependencies as &$name) { + $name = $this->nameResolver->resolve($name, $this->getNamespace()); + } + return array_unique($dependencies); } /** - * @param array $aliases + * @param NameResolver $resolver + * @return $this */ - public function setAliases(array $aliases) + public function setNameResolver(NameResolver $resolver) { - $this->aliases = $aliases; + $this->nameResolver = $resolver; + return $this; } /** @@ -162,4 +167,24 @@ public function setAbstract($bool) { public function isAbstract() { return $this->isAbstract; } + + /** + * Set the parent name + * + * @param $parent + * @return $this + */ + public function setParent($parent) { + $this->parent = $parent; + return $this; + } + + /** + * Get the parent name + * + * @return null|string + */ + public function getParent() { + return $this->nameResolver->resolve($this->parent, $this->getNamespace()); + } }; \ No newline at end of file diff --git a/src/Hal/Component/OOP/Reflected/ReflectedMethod.php b/src/Hal/Component/OOP/Reflected/ReflectedMethod.php index f2ccf8b8..fad71438 100644 --- a/src/Hal/Component/OOP/Reflected/ReflectedMethod.php +++ b/src/Hal/Component/OOP/Reflected/ReflectedMethod.php @@ -8,6 +8,7 @@ */ namespace Hal\Component\OOP\Reflected; +use Hal\Component\OOP\Resolver\NameResolver; /** @@ -48,11 +49,11 @@ class ReflectedMethod { private $dependencies = array(); /** - * Map of aliases + * Resolver for names * - * @var array + * @var NameResolver */ - private $aliases = array(); + private $nameResolver; /** * @var array @@ -70,6 +71,7 @@ class ReflectedMethod { public function __construct($name) { $this->name = (string) $name; + $this->nameResolver = new NameResolver(); } /** @@ -218,25 +220,18 @@ public function getDependencies() // on read : compare with aliases. We cannot make it in pushDependency() => aliases aren't yet known $dependencies = array(); foreach($this->dependencies as $name) { - $real = isset($this->aliases[$name]) ? $this->aliases[$name] : $name; - array_push($dependencies, $real); + array_push($dependencies, $this->nameResolver->resolve($name)); } return array_unique($dependencies); } /** - * @param array $aliases - */ - public function setAliases(array $aliases) - { - $this->aliases = $aliases; - } - - /** - * @return array + * @param NameResolver $resolver + * @return $this */ - public function getAliases() + public function setNameResolver(NameResolver $resolver) { - return $this->aliases; + $this->nameResolver = $resolver; + return $this; } }; \ No newline at end of file diff --git a/src/Hal/Component/OOP/Resolver/NameResolver.php b/src/Hal/Component/OOP/Resolver/NameResolver.php new file mode 100644 index 00000000..8280a2d7 --- /dev/null +++ b/src/Hal/Component/OOP/Resolver/NameResolver.php @@ -0,0 +1,67 @@ +<?php + +/* + * (c) Jean-François Lépine <https://twitter.com/Halleck45> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Hal\Component\OOP\Resolver; + + +/** + * Alias (and namepsace) resolver + * + * @author Jean-François Lépine <https://twitter.com/Halleck45> + */ +class NameResolver +{ + + /** + * @var array + */ + private $aliases = array(); + + /** + * Resolve name of class + * + * @param string $name + * @param string $currentNamespace + * @return string + */ + public function resolve($name, $currentNamespace = '\\') + { + // already namespaced + if ('\\' == $name[0]) { + return $name; + } + + // use xxx as yyy + if (isset($this->aliases[$name])) { + return $this->aliases[$name]; + } + + // use xxx; + foreach ($this->aliases as $alias => $nothing) { + $parts = preg_split('![^\w]!', $alias); + $last = $parts[sizeof($parts, COUNT_NORMAL) - 1]; + if ($last === $name) { + return $alias; + } + } + + return $name; + } + + /** + * Push alias + * + * @param StdClass $alias + * @return $this + */ + public function pushAlias(\StdClass $alias) { + $this->aliases[$alias->alias] = $alias->name; + return $this; + } +} \ No newline at end of file diff --git a/tests/Hal/Component/OOP/MethodExtractorTest.php b/tests/Hal/Component/OOP/MethodExtractorTest.php index c1eb6658..5f105969 100644 --- a/tests/Hal/Component/OOP/MethodExtractorTest.php +++ b/tests/Hal/Component/OOP/MethodExtractorTest.php @@ -132,7 +132,6 @@ public function provideCodeForReturns() { /** * @dataProvider provideCodeForNew - * @group wip */ public function testConstructorAreFound($expected, $code) { $searcher = new Searcher(); diff --git a/tests/Hal/Component/OOP/OOPExtractorTest.php b/tests/Hal/Component/OOP/OOPExtractorTest.php index 21759887..4f8de452 100644 --- a/tests/Hal/Component/OOP/OOPExtractorTest.php +++ b/tests/Hal/Component/OOP/OOPExtractorTest.php @@ -7,6 +7,7 @@ /** * @group oop + * @group wip */ class OOPExtractorTest extends \PHPUnit_Framework_TestCase { @@ -35,11 +36,10 @@ public function providesForClassnames() { } /** - * @group wip + * @dataProvider providesForDependenciesWithoutAlias */ - public function testDependenciesAreGivenWithoutAlias() { + public function testDependenciesAreGivenWithoutAlias($file, $expected) { - $file = __DIR__.'/../../../resources/oop/f4.php'; $result = new \Hal\Component\OOP\Extractor\Result(); $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); $result = $extractor->extract($file); @@ -50,12 +50,17 @@ public function testDependenciesAreGivenWithoutAlias() { $class = $classes[0]; $dependencies = $class->getDependencies(); - $expected = array('\Full\AliasedClass', 'Toto'); - $this->assertEquals($expected, $dependencies, 'Dependencies are given without alias'); + } + public function providesForDependenciesWithoutAlias() { + return array( + array(__DIR__.'/../../../resources/oop/f7.php', array('Symfony\Component\Config\Definition\Processor')) + , array(__DIR__.'/../../../resources/oop/f4.php', array('\Full\AliasedClass', 'Toto')) + ); } + public function testCallsAreFoundAsDependencies() { $file = __DIR__.'/../../../resources/oop/f5.php'; $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); diff --git a/tests/resources/oop/f7.php b/tests/resources/oop/f7.php new file mode 100644 index 00000000..6cdd456a --- /dev/null +++ b/tests/resources/oop/f7.php @@ -0,0 +1,12 @@ +<?php + +namespace Hal\Component\Config; +use Symfony\Component\Config\Definition\Processor; +use \Symfony\Component\Config\Definition\NodeInterface; + +class Bar { + public function foo(array $config) { + $processor = new Processor(); + return $processor->process($this->tree, $config); + } +} \ No newline at end of file