public function traverse(Project $project) { // parent classes/interfaces are visited before their "children" $classes = $project->getProjectClasses(); $modified = array(); while ($class = array_shift($classes)) { // re-push the class at the end if parent class/interfaces have not been visited yet if (($parent = $class->getParent()) && isset($classes[$parent->getName()])) { $classes[$class->getName()] = $class; continue; } foreach ($class->getInterfaces() as $interface) { if (isset($classes[$interface->getName()])) { $classes[$class->getName()] = $class; continue 2; } } $isModified = false; foreach ($this->visitors as $visitor) { $isModified = $visitor->visit($class) || $isModified; } if ($isModified) { $modified[] = $class; } } return $modified; }
protected function getStoreDir(Project $project) { $dir = $project->getCacheDir() . '/store'; if (!is_dir($dir)) { $filesystem = new Filesystem(); $filesystem->mkdir($dir); } return $dir; }
public function __construct(Project $project) { $this->hashes = array(); $this->classes = array(); foreach ($project->getProjectClasses() as $class) { $this->addClass($class); } $this->visited = array(); $this->modified = array(); }
/** * @dataProvider getTraverseOrderClasses */ public function testTraverseOrder($interfaceName, $parentName, $className, $class, $parent, $interface) { $store = new ArrayStore(); $store->setClasses(array($class, $parent, $interface)); $project = new Project($store); $visitor = $this->getMock('Sami\\Parser\\ClassVisitorInterface'); $visitor->expects($this->at(0))->method('visit')->with($project->loadClass($interfaceName)); $visitor->expects($this->at(1))->method('visit')->with($project->loadClass($parentName)); $visitor->expects($this->at(2))->method('visit')->with($project->loadClass($className)); $traverser = new ClassTraverser(); $traverser->addVisitor($visitor); $traverser->traverse($project); }
public function getIndex(Project $project) { $index = array('searchIndex' => array(), 'info' => array()); foreach ($project->getNamespaces() as $namespace) { $index['searchIndex'][] = $this->getSearchString($namespace); $index['info'][] = array(self::TYPE_NAMESPACE, $namespace); } foreach ($project->getProjectClasses() as $class) { $index['searchIndex'][] = $this->getSearchString((string) $class); $index['info'][] = array(self::TYPE_CLASS, $class); } foreach ($project->getProjectClasses() as $class) { foreach ($class->getMethods() as $method) { $index['searchIndex'][] = $this->getSearchString((string) $method); $index['info'][] = array(self::TYPE_METHOD, $method); } } return $index; }
public function getParent($deep = false) { if (!$this->parent) { return $deep ? array() : null; } $parent = $this->project->getClass($this->parent); if (false === $deep) { return $parent; } return array_merge(array($parent), $parent->getParent(true)); }
public function parse(Project $project, $callback = null) { $step = 0; $steps = iterator_count($this->iterator); $context = $this->parser->getContext(); $transaction = new Transaction($project); $toStore = new \SplObjectStorage(); foreach ($this->iterator as $file) { ++$step; $code = file_get_contents($file); $hash = sha1($code); if ($transaction->hasHash($hash)) { continue; } $context->enterFile((string) $file, $hash); $this->parser->parse($code); if (null !== $callback) { call_user_func($callback, Message::PARSE_ERROR, $context->getErrors()); } foreach ($context->leaveFile() as $class) { if (null !== $callback) { call_user_func($callback, Message::PARSE_CLASS, array(floor($step / $steps * 100), $class)); } $project->addClass($class); $transaction->addClass($class); $toStore->attach($class); $class->notFromCache(); } } // cleanup foreach ($transaction->getRemovedClasses() as $class) { $project->removeClass(new LazyClassReflection($class)); $this->store->removeClass($project, $class); } // visit each class for stuff that can only be done when all classes are parsed $toStore->addAll($this->traverser->traverse($project)); foreach ($toStore as $class) { $this->store->writeClass($project, $class); } return $transaction; }
public function getHint() { if (!$this->hint) { return array(); } $hints = array(); $project = $this->getClass()->getProject(); foreach ($this->hint as $hint) { $hints[] = new HintReflection(Project::isPhpTypeHint($hint[0]) ? $hint[0] : $project->getClass($hint[0]), $hint[1]); } return $hints; }
public function traverse(Project $project) { // parent classes/interfaces are visited before their "children" $classes = $project->getProjectClasses(); $modified = new \SplObjectStorage(); while ($class = array_shift($classes)) { // re-push the class at the end if parent class/interfaces have not been visited yet if (($parent = $class->getParent()) && isset($classes[$parent->getName()])) { $classes[$class->getName()] = $class; continue; } foreach ($interfaces = $class->getInterfaces() as $interface) { if (isset($classes[$interface->getName()])) { $classes[$class->getName()] = $class; continue 2; } } // only visits classes not coming from the cache // and for which parent/interfaces also come from the cache $visit = !$class->isFromCache() || $parent && !$parent->isFromCache(); foreach ($interfaces as $interface) { if (!$interface->isFromCache()) { $visit = true; break; } } if (!$visit) { continue; } $isModified = false; foreach ($this->visitors as $visitor) { $isModified = $visitor->visit($class) || $isModified; } if ($isModified) { $modified->attach($class); } } return $modified; }
public function __construct(Project $project = null) { $this->classes = array(); if (null !== $project) { foreach ($project->getProjectClasses() as $class) { $this->classes[$class->getName()] = $class->getHash(); } } $this->versions = array(); if (null !== $project) { foreach ($project->getVersions() as $version) { $this->versions[] = (string) $version; } } $this->namespaces = array(); if (null !== $project) { $this->namespaces = $project->getConfig('simulate_namespaces') ? $project->getSimulatedNamespaces() : $project->getNamespaces(); } }
protected function generateClassTreeLevel(Project $project, $level, array $namespaces, array $classes) { ++$level; $tree = array(); foreach ($namespaces as $namespace => $subnamespaces) { // classes if ($project->getConfig('simulate_namespaces')) { $cl = $project->getSimulatedNamespaceAllClasses($namespace); } else { $cl = $project->getNamespaceAllClasses($namespace); } // subnamespaces $ns = array(); foreach ($subnamespaces as $subnamespace) { $parts = explode('\\', $subnamespace); if (!isset($parts[$level - 1])) { continue; } $ns[implode('\\', array_slice($parts, 0, $level))][] = $subnamespace; } $parts = explode('\\', $namespace); $url = ''; if (!$project->getConfig('simulate_namespaces')) { $url = $parts[count($parts) - 1] && count($cl) ? $namespace : ''; } $short = $parts[count($parts) - 1] ? $parts[count($parts) - 1] : '[Global Namespace]'; $tree[] = array($short, $url, $this->generateClassTreeLevel($project, $level, $ns, $cl)); } foreach ($classes as $class) { if ($project->getConfig('simulate_namespaces')) { $parts = explode('_', $class->getShortName()); $short = array_pop($parts); } else { $short = $class->getShortName(); } $tree[] = array($short, $class, array()); } return $tree; }
protected function getTheme(Project $project) { return $this->themes->getTheme($project->getConfig('theme')); }
/** * Checks if the type is a php type. * * @param string $type The type. * * @return boolean */ public function isPhpType($type) { return SamiProject::isPhpTypeHint($type); }
public function render(Project $project) { $project->render(array($this, 'messageCallback'), $this->input->getOption('force')); $this->displayRenderSummary(); return count($this->errors) ? self::PARSE_ERROR : 0; }
protected function resolveAlias($alias) { // not a class if (Project::isPhpTypeHint($alias)) { return $alias; } // FQCN if ('\\' == substr($alias, 0, 1)) { return $alias; } $class = $this->context->getClass(); // special aliases if ('self' === $alias || 'static' === $alias) { return $class->getName(); } // an alias defined by a use statement $aliases = $class->getAliases(); if (isset($aliases[$alias])) { return $aliases[$alias]; } // a class in the current class namespace return $class->getNamespace() . '\\' . $alias; }
public function __construct($iterator = null, array $config = array()) { parent::__construct(); $sc = $this; if (null !== $iterator) { $this['files'] = $iterator; } $this['_versions'] = function ($sc) { $versions = isset($sc['versions']) ? $sc['versions'] : $sc['version']; if (is_string($versions)) { $versions = new Version($versions); } if ($versions instanceof Version) { $versions = new SingleVersionCollection($versions); } return $versions; }; $this['project'] = function ($sc) { $project = new Project($sc['store'], $sc['_versions'], array('build_dir' => $sc['build_dir'], 'cache_dir' => $sc['cache_dir'], 'remote_repository' => $sc['remote_repository'], 'simulate_namespaces' => $sc['simulate_namespaces'], 'include_parent_data' => $sc['include_parent_data'], 'default_opened_level' => $sc['default_opened_level'], 'theme' => $sc['theme'], 'title' => $sc['title'], 'source_url' => $sc['source_url'], 'source_dir' => $sc['source_dir'])); $project->setRenderer($sc['renderer']); $project->setParser($sc['parser']); return $project; }; $this['parser'] = function ($sc) { return new Parser($sc['files'], $sc['store'], $sc['code_parser'], $sc['traverser']); }; $this['indexer'] = function () { return new Indexer(); }; $this['tree'] = function () { return new Tree(); }; $this['parser_context'] = function ($sc) { return new ParserContext($sc['filter'], $sc['docblock_parser'], $sc['pretty_printer']); }; $this['docblock_parser'] = function () { return new DocBlockParser(); }; $this['php_parser'] = function () { return new PhpParser(new Lexer()); }; $this['php_traverser'] = function ($sc) { $traverser = new NodeTraverser(); $traverser->addVisitor(new NameResolver()); $traverser->addVisitor(new NodeVisitor($sc['parser_context'])); return $traverser; }; $this['code_parser'] = function ($sc) { return new CodeParser($sc['parser_context'], $sc['php_parser'], $sc['php_traverser']); }; $this['pretty_printer'] = function () { return new PrettyPrinter(); }; $this['filter'] = function () { return new DefaultFilter(); }; $this['store'] = function () { return new JsonStore(); }; $this['renderer'] = function ($sc) { return new Renderer($sc['twig'], $sc['themes'], $sc['tree'], $sc['indexer']); }; $this['traverser'] = function ($sc) { $visitors = array(new ClassVisitor\InheritdocClassVisitor(), new ClassVisitor\MethodClassVisitor(), new ClassVisitor\PropertyClassVisitor()); if ($sc['remote_repository'] instanceof AbstractRemoteRepository) { $visitors[] = new ClassVisitor\ViewSourceClassVisitor($sc['remote_repository']); } return new ClassTraverser($visitors); }; $this['themes'] = function ($sc) { $templates = $sc['template_dirs']; $templates[] = __DIR__ . '/Resources/themes'; return new ThemeSet($templates); }; $this['twig'] = function () { $twig = new \Twig_Environment(new \Twig_Loader_Filesystem(array('/')), array('strict_variables' => true, 'debug' => true, 'auto_reload' => true, 'cache' => false)); $twig->addExtension(new TwigExtension()); return $twig; }; $this['theme'] = 'default'; $this['title'] = 'API'; $this['version'] = 'master'; $this['template_dirs'] = array(); $this['build_dir'] = getcwd() . '/build'; $this['cache_dir'] = getcwd() . '/cache'; $this['remote_repository'] = null; $this['source_dir'] = ''; $this['source_url'] = ''; $this['default_opened_level'] = 2; // simulate namespaces for projects based on the PEAR naming conventions $this['simulate_namespaces'] = false; // include parent properties and methods on class pages $this['include_parent_data'] = true; foreach ($config as $key => $value) { $this[$key] = $value; } }
public function render(Project $project) { $callback = $this->output->isDecorated() ? array($this, 'messageCallback') : null; $project->render($callback, $this->input->getOption('force')); $this->displayRenderSummary(); }
protected function renderClassTemplates(array $classes, Project $project, $callback = null) { foreach ($classes as $class) { if (null !== $callback) { call_user_func($callback, Message::RENDER_PROGRESS, array('Class', $class->getName(), $this->getProgression())); } $variables = array('class' => $class, 'properties' => $class->getProperties($project->getConfig('include_parent_data')), 'methods' => $class->getMethods($project->getConfig('include_parent_data')), 'constants' => $class->getConstants($project->getConfig('include_parent_data'))); foreach ($this->theme->getTemplates('class') as $template => $target) { $this->save($project, sprintf($target, str_replace('\\', '/', $class->getName())), $template, $variables); } } }