Chris@0: Chris@0: * Marcello Duarte Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Prophecy\Doubler\ClassPatch; Chris@0: Chris@0: use Prophecy\Doubler\Generator\Node\ClassNode; Chris@0: use Prophecy\Doubler\Generator\Node\MethodNode; Chris@0: use Prophecy\PhpDocumentor\ClassAndInterfaceTagRetriever; Chris@0: use Prophecy\PhpDocumentor\MethodTagRetrieverInterface; Chris@0: Chris@0: /** Chris@0: * Discover Magical API using "@method" PHPDoc format. Chris@0: * Chris@0: * @author Thomas Tourlourat Chris@0: * @author Kévin Dunglas Chris@0: * @author Théo FIDRY Chris@0: */ Chris@0: class MagicCallPatch implements ClassPatchInterface Chris@0: { Chris@0: private $tagRetriever; Chris@0: Chris@0: public function __construct(MethodTagRetrieverInterface $tagRetriever = null) Chris@0: { Chris@0: $this->tagRetriever = null === $tagRetriever ? new ClassAndInterfaceTagRetriever() : $tagRetriever; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Support any class Chris@0: * Chris@0: * @param ClassNode $node Chris@0: * Chris@0: * @return boolean Chris@0: */ Chris@0: public function supports(ClassNode $node) Chris@0: { Chris@0: return true; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Discover Magical API Chris@0: * Chris@0: * @param ClassNode $node Chris@0: */ Chris@0: public function apply(ClassNode $node) Chris@0: { Chris@0: $types = array_filter($node->getInterfaces(), function ($interface) { Chris@0: return 0 !== strpos($interface, 'Prophecy\\'); Chris@0: }); Chris@0: $types[] = $node->getParentClass(); Chris@0: Chris@0: foreach ($types as $type) { Chris@0: $reflectionClass = new \ReflectionClass($type); Chris@0: Chris@17: while ($reflectionClass) { Chris@17: $tagList = $this->tagRetriever->getTagList($reflectionClass); Chris@0: Chris@17: foreach ($tagList as $tag) { Chris@17: $methodName = $tag->getMethodName(); Chris@17: Chris@17: if (empty($methodName)) { Chris@17: continue; Chris@17: } Chris@17: Chris@17: if (!$reflectionClass->hasMethod($methodName)) { Chris@17: $methodNode = new MethodNode($methodName); Chris@17: $methodNode->setStatic($tag->isStatic()); Chris@17: $node->addMethod($methodNode); Chris@17: } Chris@0: } Chris@0: Chris@17: $reflectionClass = $reflectionClass->getParentClass(); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns patch priority, which determines when patch will be applied. Chris@0: * Chris@0: * @return integer Priority number (higher - earlier) Chris@0: */ Chris@0: public function getPriority() Chris@0: { Chris@0: return 50; Chris@0: } Chris@0: } Chris@0: