/** * Calls the wkhtmltopdf executable to generate a PDF. * * @param \DOMDocument $structure Structure source * use as basis for the transformation. * @param \phpDocumentor\Transformer\Transformation $transformation Transformation * that supplies the meta-data for this writer. * * @return void */ public function transform(\DOMDocument $structure, \phpDocumentor\Transformer\Transformation $transformation) { $artifact = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact(); $transformation->setArtifact($artifact); $source = substr($transformation->getSource(), 0, 1) != DIRECTORY_SEPARATOR ? $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getSource() : $transformation->getSource(); $transformation->setSource($source); $options = ''; if ($transformation->getParameter('toc', 'false') == 'true') { $options = ' toc '; } // TODO: add parameter to provide a cover HTML // TODO: add a parameter to provide a header HTML // TODO: add a parameter to provide a footer HTML // first try if there is a wkhtmltopdf in the global path, this helps // windows users exec('wkhtmltopdf ' . $options . ' ' . $transformation->getSource() . ' ' . $transformation->getArtifact() . ' 2>&1', $output, $error); $output = implode(PHP_EOL, $output); // this notice is linux specific; if it is found no global wkhtmltopdf // was installed; try the one which is included with phpDocumentor if (strpos($output, 'wkhtmltopdf: not found') !== false) { // TODO: replace the below with a decent way to find the executable exec(dirname(__FILE__) . '/../../../src/wkhtmltopdf/wkhtmltopdf-i386 ' . $options . ' ' . $transformation->getSource() . ' ' . $transformation->getArtifact() . ' 2>&1', $output, $error); $output = implode(PHP_EOL, $output) . PHP_EOL; } // log message and output $this->log('Generating PDF file ' . $transformation->getArtifact() . ' from ' . $transformation->getSource()); $this->log($output, $error == 0 ? \phpDocumentor\Plugin\Core\Log::INFO : \phpDocumentor\Plugin\Core\Log::CRIT); // CRASH! if ($error != 0) { throw new \phpDocumentor\Plugin\Core\Exception('Conversion to PDF failed, see output for details'); } }
/** * Copies files or folders to the Artifact location. * * @param \phpDocumentor\Transformer\Transformation $transformation Transformation * to use as data source. * * @throws \Exception * * @return void */ public function executeQueryCopy(\phpDocumentor\Transformer\Transformation $transformation) { $path = $transformation->getSourceAsPath(); if (!is_readable($path)) { throw new \phpDocumentor\Transformer\Exception('Unable to read the source file: ' . $path); } if (!is_writable($transformation->getTransformer()->getTarget())) { throw new \phpDocumentor\Transformer\Exception('Unable to write to: ' . dirname($transformation->getArtifact())); } $transformation->getTransformer()->copyRecursive($path, $transformation->getArtifact()); }
/** * This method combines the structure.xml and the given target template * and creates a static html page at the artifact location. * * @param \DOMDocument $structure XML source. * @param \phpDocumentor\Transformer\Transformation $transformation Transformation. * * @throws \Exception * * @return void */ public function transform(\DOMDocument $structure, \phpDocumentor\Transformer\Transformation $transformation) { if (!class_exists('XSLTProcessor')) { throw new \phpDocumentor\Plugin\Core\Exception('The XSL writer was unable to find your XSLTProcessor; ' . 'please check if you have installed the PHP XSL extension'); } $artifact = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact(); $xsl = new \DOMDocument(); $xsl->load($transformation->getSourceAsPath()); $proc = new \XSLTProcessor(); $proc->importStyleSheet($xsl); if (empty($structure->documentElement)) { throw new \phpDocumentor\Plugin\Core\Exception('Specified DOMDocument lacks documentElement, cannot transform'); } $proc->setParameter('', 'title', $structure->documentElement->getAttribute('title')); $proc->setParameter('', 'root', str_repeat('../', substr_count($transformation->getArtifact(), '/'))); $proc->setParameter('', 'search_template', $transformation->getParameter('search', 'none')); $proc->setParameter('', 'version', \phpDocumentor\Application::VERSION); $proc->setParameter('', 'generated_datetime', date('r')); // check parameters for variables and add them when found $this->setProcessorParameters($transformation, $proc); // if a query is given, then apply a transformation to the artifact // location by replacing ($<var>} with the sluggified node-value of the // search result if ($transformation->getQuery() !== '') { $xpath = new \DOMXPath($transformation->getTransformer()->getSource()); /** @var \DOMNodeList $qry */ $qry = $xpath->query($transformation->getQuery()); $count = $qry->length; foreach ($qry as $key => $element) { \phpDocumentor\Plugin\EventDispatcher::getInstance()->dispatch('transformer.writer.xsl.pre', \phpDocumentor\Transformer\Events\PreXslWriterEvent::createInstance($this)->setElement($element)->setProgress(array($key + 1, $count))); $proc->setParameter('', $element->nodeName, $element->nodeValue); $file_name = $transformation->getTransformer()->generateFilename($element->nodeValue); $filename = str_replace('{$' . $element->nodeName . '}', $file_name, $artifact); $this->log('Processing the file: ' . $element->nodeValue . ' as ' . $filename); if (!file_exists(dirname($filename))) { mkdir(dirname($filename), 0755, true); } $proc->transformToURI($structure, $this->getXsltUriFromFilename($filename)); } } else { if (substr($transformation->getArtifact(), 0, 1) == '$') { // not a file, it must become a variable! $variable_name = substr($transformation->getArtifact(), 1); $this->xsl_variables[$variable_name] = $proc->transformToXml($structure); } else { if (!file_exists(dirname($artifact))) { mkdir(dirname($artifact), 0755, true); } $proc->transformToURI($structure, $this->getXsltUriFromFilename($artifact)); } } }
/** * Copies files or folders to the Artifact location. * * @param Transformation $transformation Transformation to use as data source. * * @throws Exception * * @return void */ public function executeQueryCopy(Transformation $transformation) { $path = $transformation->getSourceAsPath(); if (!is_readable($path)) { throw new Exception('Unable to read the source file: ' . $path); } if (!is_writable($transformation->getTransformer()->getTarget())) { throw new Exception('Unable to write to: ' . dirname($transformation->getArtifact())); } $filesystem = new Filesystem(); if (is_file($path)) { $filesystem->copy($path, $transformation->getArtifact()); } else { $filesystem->mirror($path, $transformation->getArtifact()); } }
/** * This method generates the checkstyle.xml report * * @param \DOMDocument $structure XML source. * @param \phpDocumentor\Transformer\Transformation $transformation Transformation. * * @throws \Exception * * @return void */ public function transform(\DOMDocument $structure, \phpDocumentor\Transformer\Transformation $transformation) { $artifact = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact(); $list = $structure->getElementsByTagName('parse_markers'); $document = new \DOMDocument(); $document->formatOutput = true; $report = $document->createElement('checkstyle'); $report->setAttribute('version', '1.3.0'); $document->appendChild($report); foreach ($list as $node) { $file = $document->createElement('file'); $file->setAttribute('name', $node->parentNode->getAttribute('path')); $report->appendChild($file); foreach ($node->childNodes as $error) { if ((string) $error->nodeName != '#text') { $item = $document->createElement('error'); $item->setAttribute('line', $error->getAttribute('line')); $item->setAttribute('severity', $error->nodeName); $item->setAttribute('message', $error->textContent); $item->setAttribute('source', 'phpDocumentor.phpDocumentor.phpDocumentor'); $file->appendChild($item); } } } $this->saveCheckstyleReport($artifact, $document); }
/** * Uses the currently selected node and transformation to assemble the destination path for the file. * * The Twig writer accepts the use of a Query to be able to generate output for multiple objects using the same * template. * * The given node is the result of such a query, or if no query given the selected element, and the transformation * contains the destination file. * * Since it is important to be able to generate a unique name per element can the user provide a template variable * in the name of the file. * Such a template variable always resides between double braces and tries to take the node value of a given * query string. * * Example: * * An artefact stating `classes/{{name}}.html` will try to find the * node 'name' as a child of the given $node and use that value instead. * * @param DescriptorAbstract $node * @param Transformation $transformation * * @throws \InvalidArgumentException if no artifact is provided and no routing rule matches. * * @return string|false returns the destination location or false if generation should be aborted. */ protected function getDestinationPath($node, Transformation $transformation) { $writer = $this; if (!$node) { throw new \UnexpectedValueException('The transformation node in the twig writer is not expected to be false or null'); } if (!$transformation->getArtifact()) { $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); if ($url === false || $url[0] !== DIRECTORY_SEPARATOR) { return false; } $path = $transformation->getTransformer()->getTarget() . str_replace('/', DIRECTORY_SEPARATOR, $url); } else { $path = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact(); } $destination = preg_replace_callback('/{{([^}]+)}}/u', function ($query) use($node, $writer) { // strip any surrounding \ or / return trim((string) $writer->walkObjectTree($node, $query[1]), '\\/'); }, $path); // replace any \ with the directory separator to be compatible with the // current filesystem and allow the next file_exists to do its work $destination = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $destination); // create directory if it does not exist yet if (!file_exists(dirname($destination))) { mkdir(dirname($destination), 0777, true); } return $destination; }
/** * @param \phpDocumentor\Transformer\Transformation $transformation * @return string */ protected function getDestinationPath(Transformation $transformation) { $filename = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact(); return $filename; }
/** * Creates the search index at the artifact location. * * @param \DOMDocument $structure Structure source * use as basis for the transformation. * @param \phpDocumentor\Transformer\Transformation $transformation Transformation * that supplies the meta-data for this writer. * * @return void */ public function transform(\DOMDocument $structure, \phpDocumentor\Transformer\Transformation $transformation) { $this->createXmlIndex($structure, $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact()); }
/** * 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 ); } }
/** * Uses the currently selected node and transformation to assemble the * destination path for the file. * * The Twig writer accepts the use of a Query to be able to generate output * for multiple objects using the same template. * * The given node is the result of such a query, or if no query given the * selected element, and the transformation contains the destination file. * * Since it is important to be able to generate a unique name per element * can the user provide a template variable in the name of the file. * Such a template variable always resides between braces and tries to * take the node value of a given node or attribute. * * Example: * * An artefact stating `classes/{full_name}.html` will try to find the * node 'full_name' as a child of the given $node and use that value * instead. * * An artefact stating `namespaces/{@full_name}.html` will try to find the * attribute 'full_name' of the given $node and use that value instead. * * @param \SimpleXMLElement $node * @param Transformation $transformation * * @return string */ protected function getDestinationPath(\SimpleXMLElement $node, Transformation $transformation) { $destination = preg_replace_callback('/{([^}]+)}/u', function ($query) use($node) { // replace any variable with the value of a node or attribute // where a preceeding @ denotes the value of an attribute $name = $query[1][0] === '@' ? (string) $node[substr($query[1], 1)] : (string) $node->{$query[1]}; return ltrim($name, '\\/'); // strip any preceding \ or / }, $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact()); // replace any \ with the directory separator to be compatible with the // current filesystem and allow the next file_exists to do its work $destination = str_replace('\\', DIRECTORY_SEPARATOR, $destination); // create directory if it does not exist yet if (!file_exists(dirname($destination))) { mkdir(dirname($destination), 0777, true); } return $destination; }
/** * Uses the currently selected node and transformation to assemble the destination path for the file. * * The Twig writer accepts the use of a Query to be able to generate output for multiple objects using the same * template. * * The given node is the result of such a query, or if no query given the selected element, and the transformation * contains the destination file. * * Since it is important to be able to generate a unique name per element can the user provide a template variable * in the name of the file. * Such a template variable always resides between double braces and tries to take the node value of a given * query string. * * Example: * * An artifact stating `classes/{{name}}.html` will try to find the * node 'name' as a child of the given $node and use that value instead. * * @param DescriptorAbstract $node * @param Transformation $transformation * * @throws \InvalidArgumentException if no artifact is provided and no routing rule matches. * @throws \UnexpectedValueException if the provided node does not contain anything. * * @return string|false returns the destination location or false if generation should be aborted. */ protected function getDestinationPath($node, Transformation $transformation) { $writer = $this; if (!$node) { throw new \UnexpectedValueException('The transformation node in the twig writer is not expected to be false or null'); } if (!$transformation->getArtifact()) { $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); if ($url === false || $url[0] !== DIRECTORY_SEPARATOR) { return false; } $path = $transformation->getTransformer()->getTarget() . str_replace('/', DIRECTORY_SEPARATOR, $url); } else { $path = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact(); } $finder = new Pathfinder(); $destination = preg_replace_callback('/{{([^}]+)}}/', function ($query) use($node, $writer, $finder) { // strip any surrounding \ or / $filepart = trim((string) current($finder->find($node, $query[1])), '\\/'); // make it windows proof if (extension_loaded('iconv')) { $filepart = iconv('UTF-8', 'ASCII//TRANSLIT', $filepart); } $filepart = strpos($filepart, '/') !== false ? implode('/', array_map('urlencode', explode('/', $filepart))) : implode('\\', array_map('urlencode', explode('\\', $filepart))); return $filepart; }, $path); var_dump($destination); // replace any \ with the directory separator to be compatible with the // current filesystem and allow the next file_exists to do its work $destination = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $destination); // create directory if it does not exist yet if (!file_exists(dirname($destination))) { mkdir(dirname($destination), 0777, true); } return $destination; }
/** * Returns the path to the location where the artifact should be written, or null to automatically detect the * location using the router. * * @param Transformation $transformation * * @return string|null */ private function getArtifactPath(Transformation $transformation) { return $transformation->getArtifact() ? $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact() : null; }
/** * This method writes every source code entry in the structure file * to a highlighted file. * * @param \DOMDocument $structure XML source. * @param \phpDocumentor\Transformer\Transformation $transformation Transformation. * * @throws \Exception * * @return void */ public function transform(\DOMDocument $structure, \phpDocumentor\Transformer\Transformation $transformation) { $artifact = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . ($transformation->getArtifact() ? $transformation->getArtifact() : 'source'); $xpath = new \DOMXPath($structure); $list = $xpath->query("/project/file[source]"); for ($i = 0; $i < $list->length; $i++) { /** @var \DOMElement $element */ $element = $list->item($i); $filename = $element->getAttribute('path'); $source = gzuncompress(base64_decode($element->getElementsByTagName('source')->item(0)->nodeValue)); $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 ); } }
/** * This method combines the structure.xml and the given target template * and creates a static html page at the artifact location. * * @param ProjectDescriptor $project Document containing the structure. * @param Transformation $transformation Transformation to execute. * * @return void */ public function transform(ProjectDescriptor $project, Transformation $transformation) { if (!class_exists('XSLTProcessor')) { throw new Exception('The XSL writer was unable to find your XSLTProcessor; ' . 'please check if you have installed the PHP XSL extension'); } $artifact = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact(); $xsl = new \DOMDocument(); $xsl->load($transformation->getSourceAsPath()); $structureFilename = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . 'structure.xml'; if (!is_readable($structureFilename)) { throw new RuntimeException('Structure.xml file was not found in the target directory, is the XML writer missing from the ' . 'template definition?'); } // load the structure file (ast) $structure = new \DOMDocument('1.0', 'utf-8'); libxml_use_internal_errors(true); $structure->load($structureFilename); $proc = new \XSLTProcessor(); $proc->importStyleSheet($xsl); if (empty($structure->documentElement)) { $message = 'Specified DOMDocument lacks documentElement, cannot transform.'; if (libxml_get_last_error()) { $message .= PHP_EOL . 'Apparently an error occurred with reading the structure.xml file, the reported ' . 'error was "' . trim(libxml_get_last_error()->message) . '" on line ' . libxml_get_last_error()->line; } throw new Exception($message); } $proc->setParameter('', 'title', $structure->documentElement->getAttribute('title')); $proc->setParameter('', 'root', str_repeat('../', substr_count($transformation->getArtifact(), '/'))); $proc->setParameter('', 'search_template', $transformation->getParameter('search', 'none')); $proc->setParameter('', 'version', \phpDocumentor\Application::$VERSION); $proc->setParameter('', 'generated_datetime', date('r')); // check parameters for variables and add them when found $this->setProcessorParameters($transformation, $proc); // if a query is given, then apply a transformation to the artifact // location by replacing ($<var>} with the sluggified node-value of the // search result if ($transformation->getQuery() !== '') { $xpath = new \DOMXPath($structure); /** @var \DOMNodeList $qry */ $qry = $xpath->query($transformation->getQuery()); $count = $qry->length; foreach ($qry as $key => $element) { \phpDocumentor\Event\Dispatcher::getInstance()->dispatch('transformer.writer.xsl.pre', \phpDocumentor\Transformer\Event\PreXslWriterEvent::createInstance($this)->setElement($element)->setProgress(array($key + 1, $count))); $proc->setParameter('', $element->nodeName, $element->nodeValue); $file_name = $transformation->getTransformer()->generateFilename($element->nodeValue); $filename = str_replace('{$' . $element->nodeName . '}', $file_name, $artifact); if (!file_exists(dirname($filename))) { mkdir(dirname($filename), 0755, true); } $proc->transformToURI($structure, $this->getXsltUriFromFilename($filename)); } } else { if (substr($transformation->getArtifact(), 0, 1) == '$') { // not a file, it must become a variable! $variable_name = substr($transformation->getArtifact(), 1); $this->xsl_variables[$variable_name] = $proc->transformToXml($structure); } else { if (!file_exists(dirname($artifact))) { mkdir(dirname($artifact), 0755, true); } $proc->transformToURI($structure, $this->getXsltUriFromFilename($artifact)); } } }
/** * Creates a class inheritance diagram. * * @param \DOMDocument $structure Structure * document used to gather data from. * @param \phpDocumentor\Transformer\Transformation $transformation Transformation * element containing the meta-data. * * @return void */ public function processClass(\DOMDocument $structure, \phpDocumentor\Transformer\Transformation $transformation) { $filename = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact(); $graph = \phpDocumentor\GraphViz\Graph::create()->setRankSep('1.0')->setCenter('true')->setRank('source')->setRankDir('RL')->setSplines('true')->setConcentrate('true'); $xpath = new \DOMXPath($structure); $qry = $xpath->query("/project/namespace"); /** @var \DOMElement $element */ foreach ($qry as $element) { $this->buildNamespaceTree($graph, $element, $xpath, ''); } // link all extended relations $qry = $xpath->query('/project/file/interface[extends]|/project/file/class[extends]'); /** @var \DOMElement $element */ foreach ($qry as $element) { $from_name = $element->getElementsByTagName('full_name')->item(0)->nodeValue; $to_name = $element->getElementsByTagName('extends')->item(0)->nodeValue; if (!$to_name) { continue; } $from = $graph->findNode($from_name); $to = $graph->findNode($to_name); if ($from === null) { $from = \phpDocumentor\GraphViz\Node::create($from_name); $from->setFontColor('gray'); $from->setLabel($from_name); $graph->setNode($from); } if ($to === null) { $to = \phpDocumentor\GraphViz\Node::create($to_name); $to->setFontColor('gray'); $to->setLabel($to_name); $graph->setNode($to); } $edge = \phpDocumentor\GraphViz\Edge::create($from, $to); $edge->setArrowHead('empty'); $graph->link($edge); } // link all implemented relations $qry = $xpath->query('/project/file/interface[imports]|/project/file/class[implements]'); /** @var \DOMElement $element */ foreach ($qry as $element) { $from_name = $element->getElementsByTagName('full_name')->item(0)->nodeValue; foreach ($element->getElementsByTagName('implements') as $implements) { $to_name = $implements->nodeValue; if (!$to_name) { continue; } $from = $graph->findNode($from_name); $to = $graph->findNode($to_name); if ($from === null) { $from = \phpDocumentor\GraphViz\Node::create($from_name); $from->setFontColor('gray'); $from->setLabel(addslashes($from_name)); $graph->setNode($from); } if ($to === null) { $to = \phpDocumentor\GraphViz\Node::create($to_name); $to->setFontColor('gray'); $to->setLabel(addslashes($to_name)); $graph->setNode($to); } $edge = \phpDocumentor\GraphViz\Edge::create($from, $to); $edge->setStyle('dotted'); $edge->setArrowHead('empty'); $graph->link($edge); } } $graph->export('svg', $filename); }
/** * Applies the given transformation to the provided project. * * This method will attempt to find an appropriate writer for the given transformation and invoke that with the * transformation and project so that an artifact can be generated that matches the intended transformation. * * In addition this method will emit the following events: * * - transformer.transformation.pre, before the project has been transformed with this transformation. * - transformer.transformation.post, after the project has been transformed with this transformation * * @param Transformation $transformation * @param ProjectDescriptor $project * * @uses Dispatcher to emit the events surrounding a transformation. * * @return void */ private function applyTransformationToProject(Transformation $transformation, ProjectDescriptor $project) { $this->log(sprintf(' Writer %s %s on %s', $transformation->getWriter(), $transformation->getQuery() ? ' using query "' . $transformation->getQuery() . '"' : '', $transformation->getArtifact())); $preTransformationEvent = PreTransformationEvent::createInstance($this)->setTransformation($transformation); Dispatcher::getInstance()->dispatch(self::EVENT_PRE_TRANSFORMATION, $preTransformationEvent); $writer = $this->writers[$transformation->getWriter()]; $writer->transform($project, $transformation); $postTransformationEvent = PostTransformationEvent::createInstance($this); Dispatcher::getInstance()->dispatch(self::EVENT_POST_TRANSFORMATION, $postTransformationEvent); }