/** * This method generates the checkstyle.xml report * * @param ProjectDescriptor $project Document containing the structure. * @param Transformation $transformation Transformation to execute. * * @return void */ public function transform(ProjectDescriptor $project, Transformation $transformation) { $artifact = $this->getDestinationPath($transformation); $this->checkForSpacesInPath($artifact); $document = new \DOMDocument(); $document->formatOutput = true; $report = $document->createElement('checkstyle'); $report->setAttribute('version', '1.3.0'); $document->appendChild($report); /** @var FileDescriptor $fileDescriptor */ foreach ($project->getFiles()->getAll() as $fileDescriptor) { $file = $document->createElement('file'); $file->setAttribute('name', $fileDescriptor->getPath()); $report->appendChild($file); /** @var Error $error */ foreach ($fileDescriptor->getAllErrors()->getAll() as $error) { $item = $document->createElement('error'); $item->setAttribute('line', $error->getLine()); $item->setAttribute('severity', $error->getSeverity()); $item->setAttribute('message', vsprintf($this->getTranslator()->translate($error->getCode()), $error->getContext())); $item->setAttribute('source', 'phpDocumentor.file.' . $error->getCode()); $file->appendChild($item); } } $this->saveCheckstyleReport($artifact, $document); }
/** * Iterates through each element in the project and replaces its inline @see and @link tag with a markdown * representation. * * @param ProjectDescriptor $project * * @return void */ public function execute(ProjectDescriptor $project) { /** @var Collection|DescriptorAbstract[] $elementCollection */ $this->elementCollection = $project->getIndexes()->get('elements'); foreach ($this->elementCollection as $descriptor) { $this->resolveSeeAndLinkTags($descriptor); } }
/** * {@inheritDoc} */ public function execute(ProjectDescriptor $project) { $elements = $project->getIndexes()->get('elements'); /** @var DescriptorAbstract $element */ foreach ($elements as $element) { $element->setDescription($this->replaceInlineExamples($element)); } }
/** * Creates a class inheritance diagram. * * @param ProjectDescriptor $project * @param Transformation $transformation * * @return void */ public function processClass(ProjectDescriptor $project, Transformation $transformation) { try { $this->checkIfGraphVizIsInstalled(); } catch (\Exception $e) { echo $e->getMessage(); return; } if ($transformation->getParameter('font') !== null && $transformation->getParameter('font')->getValue()) { $this->nodeFont = $transformation->getParameter('font')->getValue(); } else { $this->nodeFont = 'Courier'; } $filename = $this->getDestinationPath($transformation); $graph = GraphVizGraph::create()->setRankSep('1.0')->setCenter('true')->setRank('source')->setRankDir('RL')->setSplines('true')->setConcentrate('true'); $this->buildNamespaceTree($graph, $project->getNamespace()); $classes = $project->getIndexes()->get('classes', new Collection())->getAll(); $interfaces = $project->getIndexes()->get('interfaces', new Collection())->getAll(); $traits = $project->getIndexes()->get('traits', new Collection())->getAll(); /** @var ClassDescriptor[]|InterfaceDescriptor[]|TraitDescriptor[] $containers */ $containers = array_merge($classes, $interfaces, $traits); foreach ($containers as $container) { $from_name = $container->getFullyQualifiedStructuralElementName(); $parents = array(); $implemented = array(); if ($container instanceof ClassDescriptor) { if ($container->getParent()) { $parents[] = $container->getParent(); } $implemented = $container->getInterfaces()->getAll(); } if ($container instanceof InterfaceDescriptor) { $parents = $container->getParent()->getAll(); } /** @var string|ClassDescriptor|InterfaceDescriptor $parent */ foreach ($parents as $parent) { $edge = $this->createEdge($graph, $from_name, $parent); $edge->setArrowHead('empty'); $graph->link($edge); } /** @var string|ClassDescriptor|InterfaceDescriptor $parent */ foreach ($implemented as $parent) { $edge = $this->createEdge($graph, $from_name, $parent); $edge->setStyle('dotted'); $edge->setArrowHead('empty'); $graph->link($edge); } } $graph->export('svg', $filename); }
/** * {@inheritDoc} */ public function execute(ProjectDescriptor $project) { $elementCollection = new Collection(); $project->getIndexes()->set('elements', $elementCollection); $constantsIndex = $project->getIndexes()->get('constants', new Collection()); $functionsIndex = $project->getIndexes()->get('functions', new Collection()); $classesIndex = $project->getIndexes()->get('classes', new Collection()); $interfacesIndex = $project->getIndexes()->get('interfaces', new Collection()); $traitsIndex = $project->getIndexes()->get('traits', new Collection()); foreach ($project->getFiles() as $file) { $this->addElementsToIndexes($file->getConstants()->getAll(), array($constantsIndex, $elementCollection)); $this->addElementsToIndexes($file->getFunctions()->getAll(), array($functionsIndex, $elementCollection)); foreach ($file->getClasses()->getAll() as $element) { $this->addElementsToIndexes($element, array($classesIndex, $elementCollection)); $this->addElementsToIndexes($this->getSubElements($element), array($elementCollection)); } foreach ($file->getInterfaces()->getAll() as $element) { $this->addElementsToIndexes($element, array($interfacesIndex, $elementCollection)); $this->addElementsToIndexes($this->getSubElements($element), array($elementCollection)); } foreach ($file->getTraits()->getAll() as $element) { $this->addElementsToIndexes($element, array($traitsIndex, $elementCollection)); $this->addElementsToIndexes($this->getSubElements($element), array($elementCollection)); } } }
/** * {@inheritDoc} */ public function execute(ProjectDescriptor $project) { /** @var DescriptorAbstract $element */ foreach ($project->getIndexes()->get('elements', new Collection()) as $element) { $todos = $element->getTags()->get('todo'); if (!$todos) { continue; } /** @var TagDescriptor $todo */ foreach ($todos as $todo) { $fileDescriptor = $this->getFileDescriptor($element); $this->addTodoMarkerToFile($fileDescriptor, $todo, $element->getLine()); } } }
/** * Stores a Project Descriptor in the Cache. * * @param ProjectDescriptor $projectDescriptor * * @return void */ public function save(ProjectDescriptor $projectDescriptor) { $keys = array(); $cache = $this->getCache(); /** @var IteratorInterface $iteratorInterface */ $iteratorInterface = $cache->getIterator(); // FIXME: Workaround for: https://github.com/zendframework/zf2/pull/4154 if ($iteratorInterface->valid()) { foreach ($cache as $key) { $keys[] = $key; } } // store the settings for this Project Descriptor $cache->setItem(self::KEY_SETTINGS, $projectDescriptor->getSettings()); // store cache items $usedKeys = array(); foreach ($projectDescriptor->getFiles() as $file) { $key = self::FILE_PREFIX . md5($file->getPath()); $usedKeys[] = $key; $cache->setItem($key, $file); } // remove any keys that are no longer used. $invalidatedKeys = array_diff($keys, $usedKeys); if ($invalidatedKeys) { $cache->removeItems($invalidatedKeys); } if ($cache instanceof OptimizableInterface) { $cache->optimize(); } }
/** * Adds a class descriptor to the project's elements and add a parent file. * * @param FileDescriptor $fileDescriptor * * @return ClassDescriptor */ protected function givenProjectHasClassDescriptorAssociatedWithFile($fileDescriptor) { $classDescriptor = new ClassDescriptor(); if ($fileDescriptor) { $classDescriptor->setFile($fileDescriptor); } $elementIndex = $this->project->getIndexes()->get('elements', new Collection()); $elementIndex->add($classDescriptor); return $classDescriptor; }
/** * @covers phpDocumentor\Compiler\Pass\PackageTreeBuilder::execute * @covers phpDocumentor\Compiler\Pass\PackageTreeBuilder::addElementsOfTypeToPackage */ public function testAddFunctionToNamespace() { $function = new FunctionDescriptor(); $function->setPackage('My\\Space'); $function->setFullyQualifiedStructuralElementName('My\\Space\\Function1'); $this->project->getFiles()->get(0)->getFunctions()->add($function); // double check if a second function in the same deep namespace ends up at the right location $function2 = new FunctionDescriptor(); $function2->setPackage('My\\Space'); $function2->setFullyQualifiedStructuralElementName('My\\Space\\Function2'); $this->project->getFiles()->get(0)->getFunctions()->add($function2); $this->fixture->execute($this->project); $this->assertSame(array($function, $function2), $this->project->getIndexes()->get('packages')->get('\\My\\Space')->getFunctions()->getAll()); }
/** * @covers phpDocumentor\Descriptor\ProjectDescriptor::isVisibilityAllowed */ public function testIsVisibilityAllowed() { $this->assertTrue($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_PUBLIC)); $this->assertTrue($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_PROTECTED)); $this->assertTrue($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_PRIVATE)); $this->assertFalse($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_INTERNAL)); $settings = new Settings(); $settings->setVisibility(Settings::VISIBILITY_PROTECTED); $this->fixture->setSettings($settings); $this->assertFalse($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_PUBLIC)); $this->assertTrue($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_PROTECTED)); $this->assertFalse($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_PRIVATE)); $this->assertFalse($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_INTERNAL)); $settings->setVisibility(Settings::VISIBILITY_PROTECTED | Settings::VISIBILITY_INTERNAL); $this->fixture->setSettings($settings); $this->assertFalse($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_PUBLIC)); $this->assertTrue($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_PROTECTED)); $this->assertFalse($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_PRIVATE)); $this->assertTrue($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_INTERNAL)); }
/** * @covers phpDocumentor\Compiler\Pass\ElementsIndexBuilder::execute * @covers phpDocumentor\Compiler\Pass\ElementsIndexBuilder::addElementsToIndexes * @covers phpDocumentor\Compiler\Pass\ElementsIndexBuilder::getIndexKey * @covers phpDocumentor\Compiler\Pass\ElementsIndexBuilder::getSubElements */ public function testAddMethodsToIndex() { $file1 = $this->project->getFiles()->get(0); $classDescriptor1 = new ClassDescriptor(); $classDescriptor1->setFullyQualifiedStructuralElementName('My\\Space\\Class1'); $file1->getClasses()->add($classDescriptor1); $classMethodDescriptor1 = new MethodDescriptor(); $classMethodDescriptor1->setFullyQualifiedStructuralElementName('My\\Space\\Class1::METHOD'); $classDescriptor1->getMethods()->add($classMethodDescriptor1); $file2 = $this->project->getFiles()->get(1); $classDescriptor2 = new ClassDescriptor(); $classDescriptor2->setFullyQualifiedStructuralElementName('My\\Space\\Class2'); $file2->getClasses()->add($classDescriptor2); $classMethodDescriptor2 = new MethodDescriptor(); $classMethodDescriptor2->setFullyQualifiedStructuralElementName('My\\Space\\Class2::METHOD'); $classDescriptor2->getMethods()->add($classMethodDescriptor2); $this->fixture->execute($this->project); $elements = $this->project->getIndexes()->get('elements')->getAll(); $this->assertCount(4, $elements); $this->assertSame(array('My\\Space\\Class1', 'My\\Space\\Class1::METHOD', 'My\\Space\\Class2', 'My\\Space\\Class2::METHOD'), array_keys($elements)); $this->assertSame(array($classDescriptor1, $classMethodDescriptor1, $classDescriptor2, $classMethodDescriptor2), array_values($elements)); // class methods are not indexed separately $this->assertNull($this->project->getIndexes()->get('methods')); }
/** * Creates a tree of NamespaceDescriptors based on the provided FQNN (namespace name). * * This method will examine the namespace name and create a namespace descriptor for each part of * the FQNN if it doesn't exist in the namespaces field of the current namespace (starting with the root * Namespace in the Project Descriptor), * * As an intended side effect this method also populates the *elements* index of the ProjectDescriptor with all * created NamespaceDescriptors. Each index key is prefixed with a tilde (~) so that it will not conflict with * other FQSEN's, such as classes or interfaces. * * @param ProjectDescriptor $project * @param string $namespaceName A FQNN of the namespace (and parents) to create. * * @see ProjectDescriptor::getNamespace() for the root namespace. * @see NamespaceDescriptor::getNamespaces() for the child namespaces of a given namespace. * * @return void */ protected function createNamespaceDescriptorTree(ProjectDescriptor $project, $namespaceName) { $parts = explode('\\', ltrim($namespaceName, '\\')); $fqnn = ''; // this method does not use recursion to traverse the tree but uses a pointer that will be overridden with the // next item that is to be traversed (child namespace) at the end of the loop. $pointer = $project->getNamespace(); foreach ($parts as $part) { $fqnn .= '\\' . $part; if ($pointer->getChildren()->get($part)) { $pointer = $pointer->getChildren()->get($part); continue; } // namespace does not exist, create it $interimNamespaceDescriptor = new NamespaceDescriptor(); $interimNamespaceDescriptor->setParent($pointer); $interimNamespaceDescriptor->setName($part); $interimNamespaceDescriptor->setFullyQualifiedStructuralElementName($fqnn); // add to the pointer's list of children $pointer->getChildren()->set($part, $interimNamespaceDescriptor); // add to index $project->getIndexes()->elements['~' . $fqnn] = $interimNamespaceDescriptor; $project->getIndexes()->get('namespaces', new Collection())->add($interimNamespaceDescriptor); // move pointer forward $pointer = $interimNamespaceDescriptor; } }
/** * @covers phpDocumentor\Descriptor\ProjectDescriptorBuilder::isVisibilityAllowed */ public function testDeterminesWhetherASpecificVisibilityIsAllowedToBeIncluded() { $projectDescriptorName = 'My Descriptor'; $projectDescriptorMock = new ProjectDescriptor($projectDescriptorName); $projectDescriptorMock->getSettings()->setVisibility(Settings::VISIBILITY_PUBLIC); $this->fixture->setProjectDescriptor($projectDescriptorMock); $this->assertTrue($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_PUBLIC)); $this->assertFalse($this->fixture->isVisibilityAllowed(Settings::VISIBILITY_PRIVATE)); }
/** * @param ProjectDescriptor $project * @param $element * @return false|string */ private function generateUrlForXmlElement(ProjectDescriptor $project, $element) { $elements = $project->getIndexes()->get('elements'); $elementFqcn = ($element->parentNode->nodeName === 'namespace' ? '~\\' : '') . $element->nodeValue; $node = isset($elements[$elementFqcn]) ? $elements[$elementFqcn] : $element->nodeValue; // do not use the normalized version if the element is not found! $rule = $this->routers->match($node); if (!$rule) { throw new \InvalidArgumentException('No matching routing rule could be found for the given node, please provide an artifact location, ' . 'encountered: ' . ($node === null ? 'NULL' : get_class($node))); } $rule = new ForFileProxy($rule); $url = $rule->generate($node); return $url; }
/** * Creates a tree of PackageDescriptors based on the provided FQNN (package name). * * This method will examine the package name and create a package descriptor for each part of * the FQNN if it doesn't exist in the packages field of the current package (starting with the root * Package in the Project Descriptor), * * As an intended side effect this method also populates the *elements* index of the ProjectDescriptor with all * created PackageDescriptors. Each index key is prefixed with a tilde (~) so that it will not conflict with * other FQSEN's, such as classes or interfaces. * * @param ProjectDescriptor $project * @param string $packageName A FQNN of the package (and parents) to create. * * @see ProjectDescriptor::getPackage() for the root package. * @see PackageDescriptor::getChildren() for the child packages of a given package. * * @return void */ protected function createPackageDescriptorTree(ProjectDescriptor $project, $packageName) { $parts = explode('\\', ltrim($packageName, '\\')); $fqnn = ''; // this method does not use recursion to traverse the tree but uses a pointer that will be overridden with the // next item that is to be traversed (child package) at the end of the loop. /** @var PackageDescriptor $pointer */ $pointer = $project->getIndexes()->packages['\\']; foreach ($parts as $part) { $fqnn .= '\\' . $part; if ($pointer->getChildren()->get($part)) { $pointer = $pointer->getChildren()->get($part); continue; } // package does not exist, create it $interimPackageDescriptor = new PackageDescriptor(); $interimPackageDescriptor->setParent($pointer); $interimPackageDescriptor->setName($part); $interimPackageDescriptor->setFullyQualifiedStructuralElementName($fqnn); // add to the pointer's list of children $pointer->getChildren()->set($part ?: 'UNKNOWN', $interimPackageDescriptor); // add to index $project->getIndexes()->packages[$fqnn] = $interimPackageDescriptor; // move pointer forward $pointer = $interimPackageDescriptor; } }
/** * Ensures that the ProjectDescriptor has a root namespace with the provided array as children of that namespace. * * @param m\Mock|ProjectDescriptor $projectDescriptor * @param array $rootNamespaceChildren * * @return void */ protected function whenProjectHasTheFollowingChildrenOfRootNamespace($projectDescriptor, $rootNamespaceChildren) { $projectDescriptor->shouldReceive('getNamespace->getChildren')->andReturn(new Collection($rootNamespaceChildren)); }
/** * Executes the linker. * * @param ProjectDescriptor $project Representation of the Object Graph that can be manipulated. * * @return void */ public function execute(ProjectDescriptor $project) { $this->setObjectAliasesList($project->getIndexes()->elements->getAll()); $this->substitute($project); }
/** * Get number of markers. * * @param ProjectDescriptor $project * * @return int */ protected function getMarkerCounter(ProjectDescriptor $project) { $markerCounter = 0; /* @var $fileDescriptor FileDescriptor */ foreach ($project->getFiles()->getAll() as $fileDescriptor) { $markerCounter += $fileDescriptor->getMarkers()->count(); } return $markerCounter; }
/** * This implements testing of the protected finalize method. * * @param ProjectDescriptor $projectDescriptor * @return void */ protected function implementProtectedFinalize(ProjectDescriptor $projectDescriptor) { $this->projectDescriptor->shouldReceive('isVisibilityAllowed')->with(ProjectDescriptor\Settings::VISIBILITY_INTERNAL)->andReturn(true); }
/** * Finalizes the processing and executing all post-processing actions. * * This method is responsible for extracting and manipulating the data that * is global to the project, such as: * * - Package tree * - Namespace tree * - Marker list * - Deprecated elements listing * - Removal of objects related to visibility * * @return void */ protected function finalize(ProjectDescriptor $projectDescriptor) { // TODO: move all these behaviours to a central location for all template parsers $behaviour = new AuthorTag(); $behaviour->process($this->xml); $behaviour = new CoversTag(); $behaviour->process($this->xml); $behaviour = new IgnoreTag(); $behaviour->process($this->xml); $behaviour = new InternalTag($projectDescriptor->isVisibilityAllowed(ProjectDescriptor\Settings::VISIBILITY_INTERNAL)); $behaviour->process($this->xml); $behaviour = new LicenseTag(); $behaviour->process($this->xml); $behaviour = new MethodTag(); $behaviour->process($this->xml); $behaviour = new ParamTag(); $behaviour->process($this->xml); $behaviour = new PropertyTag(); $behaviour->process($this->xml); $behaviour = new ReturnTag(); $behaviour->process($this->xml); $behaviour = new UsesTag(); $behaviour->process($this->xml); $behaviour = new VarTag(); $behaviour->process($this->xml); $this->buildPackageTree($this->xml); $this->buildNamespaceTree($this->xml); $this->buildDeprecationList($this->xml); }
/** * This method writes every source code entry in the structure file to a highlighted file. * * @param ProjectDescriptor $project Document containing the structure. * @param Transformation $transformation Transformation to execute. * * @return void */ public function transform(ProjectDescriptor $project, Transformation $transformation) { $artifact = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . ($transformation->getArtifact() ? $transformation->getArtifact() : 'source'); /** @var FileDescriptor $file */ foreach ($project->getFiles() as $file) { $filename = $file->getPath(); $source = $file->getSource(); $root = str_repeat('../', count(explode(DIRECTORY_SEPARATOR, $filename))); $path = $artifact . DIRECTORY_SEPARATOR . $filename; if (!file_exists(dirname($path))) { mkdir(dirname($path), 0755, true); } $source = htmlentities($source); file_put_contents($path . '.html', <<<HTML <html> <head> <script type="text/javascript" src="{$root}js/jquery-1.4.2.min.js"> </script> <script type="text/javascript" src="{$root}syntax_highlighter/scripts/shCore.js"> </script> <script type="text/javascript" src="{$root}syntax_highlighter/scripts/shBrushJScript.js"> </script> <script type="text/javascript" src="{$root}syntax_highlighter/scripts/shBrushPhp.js"> </script> <script type="text/javascript" src="{$root}syntax_highlighter/scripts/shBrushXml.js"> </script> <link href="{$root}syntax_highlighter/styles/shCore.css" rel="stylesheet" type="text/css" /> <link href="{$root}syntax_highlighter/styles/shCoreEclipse.css" rel="stylesheet" type="text/css" /> <link href="{$root}syntax_highlighter/styles/shThemeWordpress.css" rel="stylesheet" type="text/css" /> </head> <body> <pre class="brush: php">{$source}</pre> <script type="text/javascript"> SyntaxHighlighter.all() jQuery('.gutter div').each(function(key, data){ jQuery(data).prepend('<a name="L'+jQuery(data).text()+'"/>'); }); </script> </body> </html> HTML ); } }