/** * Copies files or folders to the Artifact location. * * @throws Exception * * @return void */ public function executeQueryCopy(DocBlox_Transformer_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())); } $transformation->getTransformer()->copyRecursive($path, $transformation->getArtifact()); }
/** * Calls the wkhtmltopdf executable to generate a PDF. * * @param DOMDocument $structure * @param DocBlox_Transformer_Transformation $transformation * * @return void */ public function transform(DOMDocument $structure, DocBlox_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 docblox if (strpos($output, 'wkhtmltopdf: not found') !== false) { exec($this->getConfig()->paths->application . '/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 ? DocBlox_Core_Log::INFO : DocBlox_Core_Log::CRIT); // CRASH! if ($error != 0) { throw new Exception('Conversion to PDF failed, see output for details'); } }
/** * Creates a class inheritance diagram. * * @param DOMDocument $structure * @param DocBlox_Transformer_Transformation $transformation * * @return void */ public function processClass(DOMDocument $structure, DocBlox_Transformer_Transformation $transformation) { $filename = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact(); $graph = DocBlox_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(str_replace(array('\\', '$'), '_', $from_name)); $to = $graph->findNode(str_replace(array('\\', '$'), '_', $to_name)); if ($from === null) { $from = DocBlox_GraphViz_Node::create(str_replace(array('\\', '$'), '_', $from_name)); $from->setFontColor('gray'); $from->setLabel(addslashes($from_name)); $graph->setNode($from); } if ($to === null) { $to = DocBlox_GraphViz_Node::create(str_replace(array('\\', '$'), '_', $to_name)); $to->setFontColor('gray'); $to->setLabel(addslashes($to_name)); $graph->setNode($to); } $edge = DocBlox_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(str_replace(array('\\', '$'), '_', $from_name)); $to = $graph->findNode(str_replace(array('\\', '$'), '_', $to_name)); if ($from === null) { $from = DocBlox_GraphViz_Node::create(str_replace(array('\\', '$'), '_', $from_name)); $from->setFontColor('gray'); $from->setLabel(addslashes($from_name)); $graph->setNode($from); } if ($to === null) { $to = DocBlox_GraphViz_Node::create(str_replace(array('\\', '$'), '_', $to_name)); $to->setFontColor('gray'); $to->setLabel(addslashes($to_name)); $graph->setNode($to); } $edge = DocBlox_GraphViz_Edge::create($from, $to); $edge->setStyle('dotted'); $edge->setArrowHead('empty'); $graph->link($edge); } } $graph->export('svg', $filename); $svg = simplexml_load_file($filename); $script = $svg->addChild('script'); $script->addAttribute('xlink:href', 'js/SVGPan.js', 'http://www.w3.org/1999/xlink'); // for the SVGPan file to work no viewBox may be defined and the id of the first <g> node must be renamed to 'viewport' unset($svg['viewBox']); $svg->g['id'] = 'viewport'; $svg->asXML($filename); }
/** * Generates a SVG Class Diagram at the given artifact location. * * @param DOMDocument $structure * @param DocBlox_Transformer_Transformation $transformation * * @todo this method should be refactored into smaller components. * * @return void */ public function processClass(DOMDocument $structure, DocBlox_Transformer_Transformation $transformation) { $filename = $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact(); // generate graphviz $xpath = new DOMXPath($structure); $qry = $xpath->query("/project/file/class|/project/file/interface"); $extend_classes = array(); $classes = array(); /** @var DOMElement $element */ foreach ($qry as $element) { $extends = $element->getElementsByTagName('extends')->item(0)->nodeValue; if (!$extends) { $extends = 'stdClass'; } if (!isset($extend_classes[$extends])) { $extend_classes[$extends] = array(); } $extend_classes[$extends][] = $element->getElementsByTagName('full_name')->item(0)->nodeValue; $classes[] = $element->getElementsByTagName('full_name')->item(0)->nodeValue; } // find root nodes, (any class not found as extend) foreach ($extend_classes as $extend => $class_list) { if (!in_array($extend, $classes)) { // if the extend is not in the list of classes (i.e. stdClass) then we have a root node $root_nodes[] = $extend; } } if (empty($root_nodes)) { $this->log('No classes have been found, and therefore no class diagram is required', Zend_Log::INFO); return; } // traverse root nodes upwards $tree['stdClass'] = $this->buildTreenode($extend_classes); foreach ($root_nodes as $node) { if ($node === 'stdClass') { continue; } if (!isset($tree['stdClass']['?'])) { $tree['stdClass']['?'] = array(); } $tree['stdClass']['?'][$node] = $this->buildTreenode($extend_classes, $node); } $graph = new Image_GraphViz(true, array('rankdir' => 'RL', 'splines' => true, 'concentrate' => 'true', 'ratio' => '0.9'), 'Classes'); $this->buildGraphNode($graph, $tree); // disable E_STRICT reporting on the end to prevent PEAR from throwing Strict warnings. $reporting = error_reporting(); error_reporting(error_reporting() & ~E_STRICT); // render graph using Image_GraphViz $dot_file = $graph->saveParsedGraph(); $graph->renderDotFile($dot_file, $filename); error_reporting($reporting); // add panning and zooming extension $svg = simplexml_load_file($filename); $script = $svg->addChild('script'); $script->addAttribute('xlink:href', 'js/SVGPan.js', 'http://www.w3.org/1999/xlink'); // for the SVGPan file to work no viewBox may be defined and the id of the first <g> node must be renamed to 'viewport' unset($svg['viewBox']); $svg->g['id'] = 'viewport'; // save a full version // $svg->asXML(substr($filename, 0, -4) . '_full.svg'); // replace width and height with 100% on non-full version // $svg['width'] = '100%'; // $svg['height'] = '100%'; $svg->asXML($filename); }
/** * Adds the given transformation to the transformer for execution. * * It is also allowed to pass an array notation for the transformation; then this method will create * a transformation object out of it. * * The structure for this array must be: * array( * 'query' => <query>, * 'writer' => <writer>, * 'source' => <source>, * 'artifact' => <artifact>, * 'parameters' => array(<parameters>), * 'dependencies' => array(<dependencies>) * ) * * @param Transformation|array $transformation * * @return void */ public function addTransformation($transformation) { if (is_array($transformation)) { // check if all required items are present if (!key_exists('query', $transformation) || !key_exists('writer', $transformation) || !key_exists('source', $transformation) || !key_exists('artifact', $transformation)) { throw new InvalidArgumentException('Transformation array is missing elements, received: ' . var_export($transformation, true)); } $transformation_obj = new DocBlox_Transformer_Transformation($this, $transformation['query'], $transformation['writer'], $transformation['source'], $transformation['artifact']); if (isset($transformation['parameters']) && is_array($transformation['parameters'])) { $transformation_obj->setParameters($transformation['parameters']); } $transformation = $transformation_obj; } // if it is still not an object; fail if (!is_object($transformation)) { throw new InvalidArgumentException('Only transformations of type (or descended from) DocBlox_Transformer_Transformation can be used in the ' . 'transformation process; received: ' . gettype($transformation)); } // if the object is not a DocBlox_Transformer_Transformation; we cannot use it if (!$transformation instanceof DocBlox_Transformer_Transformation) { throw new InvalidArgumentException('Only transformations of type (or descended from) DocBlox_Transformer_Transformation can be used in the ' . 'transformation process; received: ' . get_class($transformation)); } $this->transformations[] = $transformation; }
/** * Sets the parameters of the XSLT processor. * * @param DocBlox_Transformer_Transformation $transformation Transformation. * @param XSLTProcessor $proc XSLTProcessor. * * @return void */ public function setProcessorParameters(DocBlox_Transformer_Transformation $transformation, XSLTProcessor $proc) { foreach ($this->xsl_variables as $key => $variable) { // XSL does not allow both single and double quotes in a string if (strpos($variable, '"') !== false && strpos($variable, "'") !== false) { $this->log('XSLT does not allow both double and single quotes in ' . 'a variable; transforming single quotes to a character ' . 'encoded version in variable: ' . $key, Zend_Log::WARN); $variable = str_replace("'", "'", $variable); } $proc->setParameter('', $key, $variable); } // add / overwrite the parameters with those defined in the // transformation entry $parameters = $transformation->getParameters(); if (isset($parameters['variables'])) { /** @var DOMElement $variable */ foreach ($parameters['variables'] as $key => $value) { $proc->setParameter('', $key, $value); } } }
/** * Populates this template from an XML source. * * @param DocBlox_Transformer $transformer The transformer which is parent. * @param string $xml The XML definition for this template. * * @return void */ public function populate(DocBlox_Transformer $transformer, $xml) { $xml = new SimpleXMLElement($xml); $this->author = $xml->author; $this->version = $xml->version; $this->copyright = $xml->copyright; foreach ($xml->transformations->transformation as $transformation) { $transformation_obj = new DocBlox_Transformer_Transformation($transformer, (string) $transformation['query'], (string) $transformation['writer'], (string) $transformation['source'], (string) $transformation['artifact']); if (isset($transformation['parameters']) && count($transformation['parameters'])) { $transformation_obj->setParameters($transformation['parameters']); } $this->transformations[] = $transformation_obj; } }
/** * Creates the search index at the artifact location. * * @param DOMDocument $structure * @param DocBlox_Transformer_Transformation $transformation * * @return void */ public function transform(DOMDocument $structure, DocBlox_Transformer_Transformation $transformation) { $this->createXmlIndex($structure, $transformation->getTransformer()->getTarget() . DIRECTORY_SEPARATOR . $transformation->getArtifact()); }
public static function createFromArray(DocBlox_Transformer $transformer, array $transformation) { // check if all required items are present if (!key_exists('query', $transformation) || !key_exists('writer', $transformation) || !key_exists('source', $transformation) || !key_exists('artifact', $transformation)) { throw new InvalidArgumentException('Transformation array is missing elements, received: ' . var_export($transformation, true)); } $transformation_obj = new DocBlox_Transformer_Transformation($transformer, $transformation['query'], $transformation['writer'], $transformation['source'], $transformation['artifact']); if (isset($transformation['parameters']) && is_array($transformation['parameters'])) { $transformation_obj->setParameters($transformation['parameters']); } return $transformation_obj; }