/** * {@inheritdoc} */ public function getUsages($identifier) { $files = $this->getQuery(['file'])->distinct()->condition('id', $identifier)->execute()->fetchCol(); $usages = new NodeCollection(); foreach ($files as $file) { $this->target->open($file)->find(Filter::isInstanceOf('\\Pharborist\\Constants\\ConstantNode'))->filter(function (ConstantNode $node) use($identifier) { return $node->getConstantName() == $identifier; })->addTo($usages); } return $usages; }
/** * Tests if a function contains logic: any branching operator, function * call, or object instantiation. * * @param \Pharborist\ParentNode $node * The node to test. * * @return boolean */ public function __invoke(ParentNode $node) { $function_calls = $node->find(Filter::isInstanceOf('\\Pharborist\\Functions\\FunctionCallNode'))->not(function (FunctionCallNode $call) { return in_array($call->getName()->getText(), $this->whitelist); }); if ($function_calls->isEmpty()) { $filter = call_user_func_array('\\Pharborist\\Filter::isInstanceOf', static::$logic); return (bool) $node->find($filter)->count(); } else { return TRUE; } }
/** * Get the use declarations of this statement block. * * @return NodeCollection|UseDeclarationNode[] * Use declarations. */ public function getUseDeclarations() { $declarations = []; /** @var \Pharborist\Namespaces\UseDeclarationBlockNode[] $use_blocks */ $use_blocks = $this->children(Filter::isInstanceOf('\\Pharborist\\Namespaces\\UseDeclarationBlockNode')); foreach ($use_blocks as $use_block) { foreach ($use_block->getDeclarationStatements() as $use_statement) { $declarations = array_merge($declarations, $use_statement->getDeclarations()->toArray()); } } return new NodeCollection($declarations, FALSE); }
/** * {@inheritdoc} */ public function convert(TargetInterface $target) { $this->target = $target; $mapping = ['DrupalWebTestCase' => 'convertWeb', 'AJAXTestCase' => 'convertAjax']; foreach ($mapping as $parent_class => $convert_method) { $test_files = $target->getIndexer('class')->getQuery(['file'])->condition('parent', $parent_class)->execute()->fetchCol(); foreach ($test_files as $test_file) { /** @var \Pharborist\Objects\Classnode[] $tests */ $tests = $target->open($test_file)->find(Filter::isInstanceOf('\\Pharborist\\Objects\\SingleInheritanceNode'))->toArray(); foreach ($tests as $test) { if ((string) $test->getExtends() === $parent_class) { $this->{$convert_method}($test); } } } } }
public function testStatic() { /** @var ClassNode $class_node */ $class_node = Parser::parseSnippet('class Foo { public $bar; }'); /** @var ClassMemberNode $a */ $a = $class_node->getProperties()[0]; $this->assertFalse($a->isStatic()); $this->assertNull($a->getStatic()); $a->setStatic(TRUE); $this->assertTrue($a->isStatic()); $this->assertSame('public static $bar;', $a->closest(Filter::isInstanceOf('\\Pharborist\\Objects\\ClassMemberListNode'))->getText()); $class_node = Parser::parseSnippet('class Bar { protected static $baz; }'); /** @var ClassMemberNode $b */ $b = $class_node->getProperties()[0]; $this->assertTrue($b->isStatic()); $this->assertInstanceOf('\\Pharborist\\TokenNode', $b->getStatic()); $this->assertSame(T_STATIC, $b->getStatic()->getType()); $b->setStatic(FALSE); $this->assertFalse($b->isStatic()); $this->assertSame('protected $baz;', $b->closest(Filter::isInstanceOf('\\Pharborist\\Objects\\ClassMemberListNode'))->getText()); }
public function testGetTypes() { $source = <<<'EOF' <?php use MyNamespace\MyClass; use MyNamespace\SomeClass as TestClass; class Test { /** * A property using class. * * @var MyClass */ private $a; /** * Property using class alias. * * @var TestClass */ private $b; /** * An array property. * * @var array */ private $data; /** * A callable property. * * @var callable */ private $callback; /** * An integer property. * * @var int */ private $num; /** * A generic property. */ private $generic; } EOF; $tree = Parser::parseSource($source); /** @var ClassNode $class */ $class = $tree->children(Filter::isInstanceOf('\\Pharborist\\Objects\\ClassNode'))[0]; $properties = $class->getProperties(); $this->assertEquals(['\\MyNamespace\\MyClass'], $properties[0]->getTypes()); $this->assertEquals(['\\MyNamespace\\SomeClass'], $properties[1]->getTypes()); $this->assertEquals(['array'], $properties[2]->getTypes()); $this->assertEquals(['callable'], $properties[3]->getTypes()); $this->assertEquals(['int'], $properties[4]->getTypes()); $this->assertEquals(['mixed'], $properties[5]->getTypes()); }
/** * Resolve an unqualified name to fully qualified name. * * @param string $name * The unqualified name to resolve. * * @return string * Fully qualified name. */ protected function resolveUnqualified($name) { if ($this->parent instanceof NamespaceNode) { return '\\' . $name; } if ($this->parent instanceof UseDeclarationNode) { return '\\' . $name; } $namespace = $this->getNamespace(); $use_declarations = array(); if ($namespace) { $use_declarations = $namespace->getBody()->getUseDeclarations(); } else { /** @var \Pharborist\RootNode $root_node */ $root_node = $this->closest(Filter::isInstanceOf('\\Pharborist\\RootNode')); if ($root_node) { $use_declarations = $root_node->getUseDeclarations(); } } if ($this->parent instanceof FunctionCallNode) { /** @var UseDeclarationNode $use_declaration */ foreach ($use_declarations as $use_declaration) { if ($use_declaration->isFunction() && $use_declaration->getBoundedName() === $name) { return '\\' . $use_declaration->getName()->getPath(); } } return $this->getParentPath() . $name; } elseif ($this->parent instanceof ConstantNode) { /** @var UseDeclarationNode $use_declaration */ foreach ($use_declarations as $use_declaration) { if ($use_declaration->isConst() && $use_declaration->getBoundedName() === $name) { return '\\' . $use_declaration->getName()->getPath(); } } return $this->getParentPath() . $name; } else { // Name is a class reference. /** @var UseDeclarationNode $use_declaration */ foreach ($use_declarations as $use_declaration) { if ($use_declaration->isClass() && $use_declaration->getBoundedName() === $name) { return '\\' . $use_declaration->getName()->getPath(); } } // No use declaration so class name refers to class in current namespace. return $this->getParentPath() . $name; } }
/** * Returns if the array has a specific key. * * @param mixed $key * Either a scalar value ('foo') or an ExpressionNode representing the key. * If $key is an ExpressionNode, the key's string representation is compared * with the string representations of the array keys. Otherwise, the actual * value is compared. * @param boolean $recursive * Whether or not to check every level of the array. * * @return boolean * * @throws \InvalidArgumentException */ public function hasKey($key, $recursive = TRUE) { if (!$key instanceof ExpressionNode && !is_scalar($key)) { throw new \InvalidArgumentException(); } $keys = $this->getKeys($recursive); if (is_scalar($key)) { return $keys->filter(Filter::isInstanceOf('\\Pharborist\\Types\\ScalarNode'))->is(function (ScalarNode $node) use($key) { return $node->toValue() === $key; }); } else { return $keys->is(function (ExpressionNode $expr) use($key) { return $expr->getText() === $key->getText(); }); } }
/** * Returns every namespace in this document. * * @return \Pharborist\NodeCollection */ public function getNamespaces() { return $this->children(Filter::isInstanceOf('\\Pharborist\\Namespaces\\NamespaceNode')); }
/** * Returns if the parameter is fully reassigned anywhere in the function. * * @param \Pharborist\Functions\ParameterNode $parameter * The parameter to check. * * @return boolean */ protected function isReassigned(ParameterNode $parameter) { return (bool) $parameter->getFunction()->find(Filter::isInstanceOf('\\Pharborist\\Variables\\VariableNode'))->filter(function (VariableNode $variable) use($parameter) { return $variable->getName() == $parameter->getName(); })->filter($this->isAssigned)->count(); }
/** * Parses a generated class into a syntax tree. * * @param string|array $class * The class to parse, either as a string of PHP code or a renderable array. * * @return \Pharborist\Objects\ClassNode */ protected function parse($class) { if (is_array($class)) { $class = \Drupal::service('renderer')->renderPlain($class); } return Parser::parseSnippet($class)->find(Filter::isInstanceOf('Pharborist\\Objects\\ClassNode'))[0]; }
/** * Test template file. */ public function testTemplate() { $source = <<<'EOF' <p>This is a template file</p> <p>Hello, <?=$name?>. Welcome to <?=$lego . 'world'?>!</p> <?php code(); ?><h1>End of template</h1><?php more_code(); EOF; $tree = Parser::parseSource($source); $this->assertEquals($source, $tree->getText()); /** @var TemplateNode[] $templates */ $templates = $tree->find(Filter::isInstanceOf('\\Pharborist\\TemplateNode')); $template = $templates[0]; $this->assertEquals(5, $template->childCount()); /** @var EchoTagStatementNode $echo_tag */ $echo_tag = $template->firstChild()->next(); $this->assertInstanceOf('\\Pharborist\\EchoTagStatementNode', $echo_tag); $this->assertEquals('<?=$name?>', $echo_tag->getText()); $expressions = $echo_tag->getExpressions(); $this->assertEquals('$name', $expressions[0]->getText()); $template = $templates[1]; $this->assertEquals('?><h1>End of template</h1><?php ', $template->getText()); }
/** * @return NodeCollection */ public function getOptionalParameters() { return $this->parameters->children(Filter::isInstanceOf('\\Pharborist\\ParameterNode'))->filter(function (ParameterNode $parameter) { $value = $parameter->getValue(); return isset($value); }); }
/** * {@inheritdoc} */ public function buildRoute(TargetInterface $target, Drupal7Route $route) { $definition = $this->buildRouteDefinition($target, $route); $map = $this->buildParameterMap($target, $route); $map->applyRoute($definition->unwrap()); $indexer = $target->getIndexer('function'); foreach ($map->toArray() as $function_name => $parameters) { if ($parameters && $indexer->has($function_name)) { /** @var \Pharborist\Functions\FunctionDeclarationNode $function */ $function = $indexer->get($function_name); foreach ($parameters as $parameter_name => $info) { $parameter = $function->getParameterByName($parameter_name)->setName($info['name'], TRUE); if (isset($info['type'])) { $plugin_id = '_rewriter:' . $info['type']; if ($this->rewriters->hasDefinition($plugin_id)) { $this->rewriters->createInstance($plugin_id)->rewrite($parameter); } } } } } $class_indexer = $target->getIndexer('class'); if ($class_indexer->has('DefaultController')) { $controller = $class_indexer->get('DefaultController'); } else { $controller = $this->getController($target, $route); $class_indexer->addFile($this->writeClass($target, $controller)); } if ($indexer->has($route['title callback'])) { if (!$controller->hasMethod($route['title callback'])) { $indexer->get($route['title callback'])->cloneAsMethodOf($controller); } } if ($indexer->has($route['access callback'])) { $func = $indexer->get($route['access callback']); $returns = $func->find(Filter::isInstanceOf('\\Pharborist\\ReturnStatementNode')); foreach ($returns as $ret) { $call = ClassMethodCallNode::create('\\Drupal\\Core\\Access\\AccessResult', 'allowedIf')->appendArgument($ret->getExpression()); $ret->replaceWith(ReturnStatementNode::create($call)); } // The access callback always receives an $account parameter. if ($func->hasParameter('account')) { $func->getParameter('account')->setTypeHint('Drupal\\Core\\Session\\AccountInterface'); } else { $account = ParameterNode::create('account')->setTypeHint('Drupal\\Core\\Session\\AccountInterface'); $func->appendParameter($account); } if (!$controller->hasMethod($route['access callback'])) { $func->cloneAsMethodOf($controller); } } if ($indexer->has($route['page callback'])) { if (!$controller->hasMethod($route['page callback'])) { $indexer->get($route['page callback'])->cloneAsMethodOf($controller); } } $this->writeClass($target, $controller); }
public function getRoot() { return $this->closest(Filter::isInstanceOf('\\Pharborist\\RootNode')); }
/** * @requires PHP 5.6 */ public function testVariadic() { $source = <<<'EOF' <?php function foo($args) { } EOF; $tree = Parser::parseSource($source); /** @var \Pharborist\Functions\FunctionDeclarationNode $function */ $function = $tree->children(Filter::isInstanceOf('\\Pharborist\\Functions\\FunctionDeclarationNode'))[0]; $parameter = $function->getParameter(0); $this->assertFalse($parameter->isVariadic()); $parameter->setVariadic(TRUE); $this->assertTrue($parameter->isVariadic()); $this->assertEquals('...$args', $parameter->getText()); }
/** * A helper function to ease exception catching in the __toString() method. * * @return string */ protected function toString() { $doc = RootNode::create($this->getNamespace()); $class = ClassNode::create($this->getName()); $constructor = ClassMethodNode::create('__construct'); $class->appendMethod($constructor); $constructorDocString = ''; foreach ($this->getProperties() as $name => $info) { $class->createProperty($name, isset($info['default']) ? $info['default'] : NULL, 'protected'); if (isset($info['description'])) { $propertyDocString = "@var {$info['type']} {$name}\n {$info['description']}"; $constructorDocString .= "@param {$info['type']} {$name}\n {$info['description']}\n\n"; } else { $propertyDocString = "@var {$info['type']} {$name}"; $constructorDocString .= "@param {$info['type']} {$name}\n\n"; } $class->getProperty($name)->closest(Filter::isInstanceOf('\\Pharborist\\Objects\\ClassMemberListNode'))->setDocComment(DocCommentNode::create($propertyDocString)); $constructor->appendParameter(ParameterNode::create($name)); $expression = Parser::parseSnippet("\$this->{$name} = \${$name};"); $constructor->getBody()->lastChild()->before($expression); $getter = ClassMethodNode::create('get' . ucfirst($name)); $class->appendMethod($getter); $class->getMethod('get' . ucfirst($name))->setDocComment(DocCommentNode::create("Gets the {$name} value.")); $getter_expression = Parser::parseSnippet("return \$this->{$name};"); $getter->getBody()->lastChild()->before($getter_expression); } $class->getMethod('__construct')->setDocComment(DocCommentNode::create($constructorDocString)); $doc->getNamespace($this->getNamespace())->getBody()->append($class); /* @todo dispatch an event to allow subscribers to alter $doc */ $formatter = FormatterFactory::getPsr2Formatter(); $formatter->format($doc->getNamespace($this->getNamespace())); return $doc->getText(); }
/** * {@inheritdoc} */ public function addFile($path) { $doc = Parser::parseFile($path); $doc->children(Filter::isInstanceOf('\\Pharborist\\Functions\\FunctionDeclarationNode'))->each([$this, 'add']); $doc->find(Filter::isInstanceOf('\\Pharborist\\Functions\\FunctionCallNode'))->each([$this, 'add']); }
/** * @param SingleInheritanceNode|InterfaceNode $node */ protected function endClassTraitOrInterface($node) { $nl = $this->config['nl']; $indent = str_repeat(' ', $this->config['indent']); $indent = str_repeat($indent, $this->indentLevel + 1); /** @var WhitespaceNode $ws_node */ $whitespace = $node->getBody()->children(Filter::isInstanceOf('\\Pharborist\\WhitespaceNode')); foreach ($whitespace->slice(1, -1) as $ws_node) { // Blank line between methods and properties. $ws_node->setText(str_repeat($nl, 2) . $indent); } if ($whitespace->count() === 1) { return; } $blank_lines_around_class_body = $this->config['blank_lines_around_class_body']; $nl_count = $blank_lines_around_class_body + 1; /** @var WhitespaceNode $open_whitespace */ $open_whitespace = $whitespace->get(0); $open_whitespace->setText(str_repeat($nl, $nl_count) . $indent); /** @var WhitespaceNode $close_whitespace */ $close_whitespace = $whitespace->last()->get(0); $indent = str_repeat($indent, $this->indentLevel); $close_whitespace->setText(str_repeat($nl, $nl_count) . $indent); }
/** * Sets the imported item's alias. If NULL is passed, the alias is removed. * * @param \Pharborist\TokenNode|string|NULL $alias * * @return $this */ public function setAlias($alias) { if (is_string($alias)) { $alias = new TokenNode(T_STRING, $alias); } if ($alias instanceof TokenNode) { if ($this->hasAlias()) { $this->alias->replaceWith($alias); } else { $this->alias = $alias; $this->addChild(WhitespaceNode::create(' ')); $this->addChild(Token::_as()); $this->addChild(WhitespaceNode::create(' ')); $this->addChild($alias, 'alias'); } } elseif ($alias === NULL && $this->hasAlias()) { $this->alias->previousUntil(Filter::isInstanceOf('\\Pharborist\\Namespaces\\NameNode'))->remove(); $this->alias->remove(); $this->alias = NULL; } else { throw new \InvalidArgumentException(); } return $this; }
/** * @param ExpressionNode|NULL $node * @return $this */ public function setValue($node) { if ($node === NULL) { if (isset($this->value)) { $this->value->previousUntil(Filter::isInstanceOf('\\Pharborist\\Variables\\VariableNode'))->remove(); $this->value->remove(); } } else { if (isset($this->value)) { /** @var Node $node */ $this->value->replaceWith($node); } else { $this->append([Token::space(), Token::assign(), Token::space(), $node]); } } return $this; }
/** * @return NodeCollection|ConstantDeclarationNode[] */ public function getConstants() { $constants = []; /** @var ConstantDeclarationStatementNode $node */ foreach ($this->statements->children(Filter::isInstanceOf('\\Pharborist\\Constants\\ConstantDeclarationStatementNode')) as $node) { $constants = array_merge($constants, $node->getDeclarations()->toArray()); } return new NodeCollection($constants, FALSE); }
/** * Add property to class. * * @param string|ClassMemberListNode $property * @return $this */ public function appendProperty($property) { if (is_string($property)) { $property = ClassMemberListNode::create($property); } $properties = $this->statements->children(Filter::isInstanceOf('\\Pharborist\\ClassMemberListNode')); if ($properties->count() === 0) { $this->statements->firstChild()->after($property); } else { $properties->last()->after($property); } FormatterFactory::format($this); return $this; }
/** * Gets the fully qualified name of the method, e.g. \My\Namespaced\Class::foo. * * @return string */ public function getFullyQualifiedName() { /** @var ClassNode $class_node */ $class_node = $this->closest(Filter::isInstanceOf('\\Pharborist\\Objects\\ClassNode')); return $class_node->getName()->getAbsolutePath() . '::' . $this->getName()->getText(); }
/** * Tests if the given node is on the left side of an assignment. * * @param \Pharborist\Node $node * The node to test. * * @return boolean */ public function __invoke(Node $node) { /** @var \Pharborist\Operators\AssignNode $assignment */ $assignment = $node->closest(Filter::isInstanceOf('\\Pharborist\\Operators\\AssignNode')); return $assignment ? $assignment->getLeftOperand() === $node : FALSE; }
/** * @return NodeCollection|InterfaceMethodNode[] */ public function getMethods() { return $this->statements->children(Filter::isInstanceOf('\\Pharborist\\Objects\\InterfaceMethodNode')); }