Beispiel #1
0
 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);
 }
Beispiel #5
0
 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));
 }
Beispiel #7
0
 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;
 }
Beispiel #8
0
 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;
 }
Beispiel #9
0
 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();
     }
 }
Beispiel #11
0
 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;
 }
Beispiel #12
0
 protected function getTheme(Project $project)
 {
     return $this->themes->getTheme($project->getConfig('theme'));
 }
Beispiel #13
0
 /**
  * Checks if the type is a php type.
  *
  * @param  string  $type The type.
  *
  * @return boolean
  */
 public function isPhpType($type)
 {
     return SamiProject::isPhpTypeHint($type);
 }
Beispiel #14
0
 public function render(Project $project)
 {
     $project->render(array($this, 'messageCallback'), $this->input->getOption('force'));
     $this->displayRenderSummary();
     return count($this->errors) ? self::PARSE_ERROR : 0;
 }
Beispiel #15
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;
 }
Beispiel #16
0
 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);
         }
     }
 }