/**
  * Main entry point into the application.
  *
  * @return void
  */
 public function main()
 {
     $runner = new DocBlox_Task_Runner($_SERVER['argc'] == 1 ? false : $_SERVER['argv'][1], 'project:run');
     $task = $runner->getTask();
     $threshold = DocBlox_Core_Log::WARN;
     if (!$task->getQuiet()) {
         DocBlox_Core_Application::renderVersion();
     } else {
         $threshold = DocBlox_Core_Log::QUIET;
     }
     if ($task->getVerbose()) {
         $threshold = DocBlox_Core_Log::DEBUG;
     }
     $dispatcher = new sfEventDispatcher();
     $logger = new DocBlox_Core_Log(DocBlox_Core_Log::FILE_STDOUT);
     $logger->setThreshold($threshold);
     $dispatcher->connect('system.log', array($logger, 'log'));
     DocBlox_Parser_Abstract::$event_dispatcher = $dispatcher;
     DocBlox_Transformer_Abstract::$event_dispatcher = $dispatcher;
     DocBlox_Reflection_Abstract::$event_dispatcher = $dispatcher;
     try {
         $task->execute();
     } catch (Exception $e) {
         if (!$task->getQuiet()) {
             echo 'ERROR: ' . $e->getMessage() . PHP_EOL . PHP_EOL;
             echo $task->getUsageMessage();
         }
         die(1);
     }
 }
Exemple #2
0
 /**
  * Adds extra information to the structure.
  *
  * This method enhances the Structure information with the following information:
  * - Every file receives a 'generated-path' attribute which contains the path on the filesystem where the docs for
  *   that file van be found.
  *
  * @param DOMDocument $xml
  *
  * @return DOMDocument
  */
 public function process(DOMDocument $xml)
 {
     if ($this->logger) {
         $this->logger->log('Adding path information to each xml "file" tag');
     }
     $xpath = new DOMXPath($xml);
     $qry = $xpath->query("/project/file[@path]");
     /** @var DOMElement $element */
     foreach ($qry as $element) {
         $files[] = $element->getAttribute('path');
         $element->setAttribute('generated-path', $this->generateFilename($element->getAttribute('path')));
     }
     return $xml;
 }
Exemple #3
0
 /**
  * Removes DocBlocks marked with 'ignore' tag from the structure
  *
  * @param DOMDocument $xml
  *
  * @return DOMDocument
  */
 public function process(DOMDocument $xml)
 {
     if ($this->logger) {
         $this->logger->log('Removing DocBlocks containing the @' . $this->tag . ' tag');
     }
     $ignoreQry = '//tag[@name=\'' . $this->tag . '\']';
     $xpath = new DOMXPath($xml);
     $nodes = $xpath->query($ignoreQry);
     /** @var DOMElement $node */
     foreach ($nodes as $node) {
         $remove = $node->parentNode->parentNode;
         $node->parentNode->parentNode->parentNode->removeChild($remove);
     }
     return $xml;
 }
Exemple #4
0
 /**
  * Apply inheritance of docblock elements to all elements.
  *
  * Apply the inheritance rules from root node to edge leaf; this way the
  * inheritance cascades.
  *
  * Note: the process below must _first_ be done on interfaces and a second
  * pass on classes. If this is not done then not everything will be picked
  * up because you effectively have 2 separate sets of root nodes.
  *
  * This does mean that an interface will populate any class in which it is
  * implemented but will not walk further down the tree.
  *
  * Interfaces do not check whether they implement another interface because
  * interfaces do not support the IMPLEMENTS keyword.
  *
  * Actions:
  *
  * 1. Get root nodes with present leafs
  * 2. Get Extended/implemented leafs
  * 3. If SD misses for leaf; apply SD of root
  * 4. If LD misses for leaf; apply LD of root
  * 5. if LD of leaf contains {@inheritdoc}; replace with LD of root
  * 6. if @category of leaf is missing; use @category of root
  * 7. if @package of leaf is missing; use @package of root
  * 8. if @subcategory of leaf is missing; use @subpackage of root
  * 9. if @version of leaf is missing; use @version of root
  * 10. if @copyright of leaf is missing; use @copyright of root
  * 11. if @author of leaf is missing; use @author of root
  *
  * 12. If root and leaf share a method with the same name:
  * 13. If SD misses for leaf method; apply SD of root method
  * 14. If LD misses for leaf method; apply LD of root method
  * 15. if LD of leaf method contains {@inheritdoc}; replace with LD of root method
  * 16. if @params of leaf method is missing; use @params of root method
  * 17. if @return of leaf method is missing; use @return of root method
  * 18. if @throw/throws of leaf method is missing; use @throws/throw of root method
  * 19. if @version of leaf method is missing; use @version of root method
  * 20. if @copyright of leaf method is missing; use @copyright of root method
  * 21. if @author of leaf method is missing; use @author of root method
  *
  * 22. If root and leaf share a property with the same name:
  * 23. If SD misses for leaf property; apply SD of root property
  * 24. If LD misses for leaf property; apply LD of root property
  * 25. if LD of leaf property contains {@inheritdoc}; replace with LD of root property
  * 26. if @var of leaf property is missing; use @var of root property
  * 27. if @version of leaf property is missing; use @version of root property
  * 28. if @copyright of leaf property is missing; use @copyright of root property
  * 29. if @author of leaf property is missing; use @author of root property
  *
  * @param DOMDocument $xml
  *
  * @return DOMDocument
  */
 public function process(DOMDocument $xml)
 {
     if ($this->logger) {
         $this->logger->log('Adding path information to each xml "file" tag');
     }
     $xpath = new DOMXPath($xml);
     // get all interfaces that do not extend from anything or whose extend
     // is not featured in this project; these are considered root nodes.
     /** @var DOMElement[] $result */
     $result = $xpath->query('/project/file/interface[extends=""]' . '|/project/file/interface[not(extends = /project/file/class/full_name)]');
     foreach ($result as $node) {
         $inherit = new DocBlox_Transformer_Behaviour_Inherit_Node_Interface($node, $xpath);
         $super = array('classes' => array(), 'properties' => array(), 'methods' => array());
         $inherit->apply($super, null);
     }
     // get all classes that do not extend from anything or whose extend
     // is not featured in this project; these are considered root nodes.
     /** @var DOMElement[] $result */
     $result = $xpath->query('/project/file/class[extends=""]' . '|/project/file/class[not(extends = /project/file/class/full_name)]');
     foreach ($result as $node) {
         $inherit = new DocBlox_Transformer_Behaviour_Inherit_Node_Class($node, $xpath);
         $super = array('classes' => array(), 'properties' => array(), 'methods' => array());
         $inherit->apply($super, null);
     }
     return $xml;
 }
Exemple #5
0
 /**
  * Find all return tags that contain 'self' or '$this' and replace those
  * terms for the name of the current class' type.
  *
  * @param DOMDocument $xml
  *
  * @return DOMDocument
  */
 public function process(DOMDocument $xml)
 {
     if ($this->logger) {
         $this->logger->log('Transforming `self` and `$this` statements for @return tags');
     }
     $ignoreQry = '//tag[@name=\'return\' and @type=\'\\self\']' . '|//tag[@name=\'return\' and @type=\'\\$this\']' . '|//tag[@name=\'return\']/type[.=\'\\self\']' . '|//tag[@name=\'return\']/type[.=\'\\$this\']';
     $xpath = new DOMXPath($xml);
     $nodes = $xpath->query($ignoreQry);
     /** @var DOMElement $node */
     foreach ($nodes as $node) {
         // if a node with name 'type' is selected we need to reach one
         // level further.
         $docblock = $node->nodeName == 'type' ? $node->parentNode->parentNode : $node->parentNode;
         $method = $docblock->parentNode;
         // find the name of the method
         $method_name = $method->getElementsByTagName('name')->item(0)->nodeValue;
         // if the method is not a method but a global function: error!
         if ($method->nodeName != 'method') {
             $this->logger->log('Global function ' . $method_name . ' contains a reference ' . 'to self or $self', DocBlox_Core_Log::ERR);
             continue;
         }
         $type = $method->parentNode->getElementsByTagName('full_name')->item(0)->nodeValue;
         // nodes with name type need to set their content; otherwise we set
         // an attribute of the class itself
         if ($node->nodeName == 'type') {
             $node->nodeValue = $type;
             // add a new tag @fluent to indicate that this is a fluent interface
             // we only add it here since there should always be a node `type`
             $fluent_tag = new DOMElement('tag');
             $docblock->appendChild($fluent_tag);
             $fluent_tag->setAttribute('name', 'fluent');
             $fluent_tag->setAttribute('description', 'This method is part of a fluent interface and will return ' . 'the same instance');
         } else {
             $node->setAttribute('type', $type);
         }
         // check if an excerpt is set and override that as well
         if ($node->hasAttribute('excerpt') && ($node->getAttribute('excerpt') == '\\self' || $node->getAttribute('excerpt') == '\\$this')) {
             $node->setAttribute('excerpt', $type);
         }
     }
     return $xml;
 }
 /**
  * Logs the message to the log with the given priority.
  *
  * This method only works if the Log Level is higher than the given priority.
  * If there is no logger object than this method will instantiate it.
  * In contrary to the debug statement this only logs strings.
  *
  * @param string $message  Element to log.
  * @param int    $priority Priority of the given log.
  *
  * @see DocBlock_Abstract::setLogLevel()
  * @see Zend_Log
  *
  * @return void
  */
 public function log($message, $priority = DocBlox_Core_Log::INFO)
 {
     if ($priority == DocBlox_Core_Log::DEBUG) {
         $this->debug($message);
         return;
     }
     if (!self::$logger || !self::$stdout_logger) {
         $config = $this->getConfig();
         // log to file
         self::$logger = new DocBlox_Core_Log($config->logging->paths->default);
         self::$logger->setThreshold($this->getLogLevel());
         // log to stdout
         self::$stdout_logger = new DocBlox_Core_Log(DocBlox_Core_Log::FILE_STDOUT);
         self::$stdout_logger->setThreshold($this->getLogLevel());
     }
     self::$logger->log($message, $priority);
     self::$stdout_logger->log($message, $priority);
 }
 public function testLog()
 {
     if (file_exists('/tmp/DocBlox_Core_Log_test')) {
         unlink('/tmp/DocBlox_Core_Log_test');
     }
     $this->fixture = new DocBlox_Core_Log('/tmp/DocBlox_Core_Log_test');
     $this->fixture->setThreshold(DocBlox_Core_Log::ERR);
     $this->fixture->log('test', DocBlox_Core_Log::ERR);
     $this->fixture->log('test2', DocBlox_Core_Log::INFO);
     $result = file_get_contents('/tmp/DocBlox_Core_Log_test');
     $this->assertNotEmpty($result);
     $this->assertContains('test', $result);
     $this->assertNotContains('mb]:', $result, 'Should not contain debug information');
     $this->assertNotContains('test2', $result, 'Should not contain test2 as it is of a lower level');
     $this->fixture->setThreshold(DocBlox_Core_Log::DEBUG);
     $this->fixture->log('test3', DocBlox_Core_Log::INFO);
     $result = file_get_contents('/tmp/DocBlox_Core_Log_test');
     $this->assertContains('test3', $result);
     $this->assertContains('mb]:', $result, 'Should contain debug information when threshold is DEBUG');
     $this->fixture->log(array('test4'), DocBlox_Core_Log::INFO);
     $result = file_get_contents('/tmp/DocBlox_Core_Log_test');
     $this->assertContains('array', $result, 'The log should contain a var_dumped output');
 }
Exemple #8
0
 /**
  * Logs the given to a debug log.
  *
  * If anything other than a string is passed than the item is var_dumped
  * and then stored.
  *
  * @param string|array|object $message Item to log.
  *
  * @return void
  */
 public function log($message)
 {
     $this->logger->log($message, DocBlox_Core_Log::DEBUG);
 }
Exemple #9
0
 /**
  * Adds extra information to the structure.
  *
  * This method enhances the Structure information with the following information:
  * - Every @see tag, or a tag with a type receives an attribute with a direct link to that tag's type entry.
  * - Every tag receives an excerpt containing the first 15 characters.
  *
  * @param DOMDocument $xml
  *
  * @return DOMDocument
  */
 public function process(DOMDocument $xml)
 {
     if ($this->logger) {
         $this->logger->log('Adding path information to each xml "file" tag');
     }
     $xpath = new DOMXPath($xml);
     // add to classes
     $qry = $xpath->query('//class[full_name]/..');
     $class_paths = array();
     /** @var DOMElement $element */
     foreach ($qry as $element) {
         $path = $element->getAttribute('path');
         foreach ($element->getElementsByTagName('class') as $class) {
             $class_paths[$class->getElementsByTagName('full_name')->item(0)->nodeValue] = $path;
         }
     }
     // add to interfaces
     $qry = $xpath->query('//interface[full_name]/..');
     /** @var DOMElement $element */
     foreach ($qry as $element) {
         $path = $element->getAttribute('path');
         /** @var DOMElement $class */
         foreach ($element->getElementsByTagName('interface') as $class) {
             $class_paths[$class->getElementsByTagName('full_name')->item(0)->nodeValue] = $path;
         }
     }
     // add extra xml elements to tags
     if ($this->logger) {
         $this->logger->log('Adding link information and excerpts to all DocBlock tags');
     }
     $qry = $xpath->query('//docblock/tag/@type|//docblock/tag/type|//extends|//implements');
     $declared_classes = get_declared_classes();
     /** @var DOMElement $element */
     foreach ($qry as $element) {
         $type = rtrim($element->nodeValue, '[]');
         $node = $element->nodeType == XML_ATTRIBUTE_NODE ? $element->parentNode : $element;
         // if the class is already loaded and is an internal class; refer
         // to the PHP man pages
         if (in_array(ltrim($type, '\\'), $declared_classes)) {
             $refl = new ReflectionClass($type);
             if ($refl->isInternal()) {
                 $node->setAttribute('link', 'http://php.net/manual/en/class.' . strtolower(ltrim($type, '\\')) . '.php');
             }
         }
         if (isset($class_paths[$type])) {
             $file_name = $this->generateFilename($class_paths[$type]);
             $node->setAttribute('link', $file_name . '#' . $type);
         }
         // add a 15 character excerpt of the node contents, meant for the sidebar
         $node->setAttribute('excerpt', utf8_encode(substr($type, 0, 15) . (strlen($type) > 15 ? '...' : '')));
     }
     // convert class names to links
     // this action also checks the link of an @link tag it it starts with
     // `http://`, `https://` or `www.`. if not: also convert those.
     $qry = $xpath->query('//docblock/tag[@name="see" or @name="throw" or @name="throws"]' . '|//docblock/tag[@name="link" ' . 'and (substring(@link,1,7) != \'http://\' ' . 'or substring(@link,1,4) != \'www.\'' . 'or substring(@link,1,7) != \'https://\')]');
     /** @var DOMElement $element */
     foreach ($qry as $element) {
         $name = $element->getAttribute('name') == 'link' ? $element->getAttribute('link') : $element->nodeValue;
         $node_value = explode('::', $name);
         if (isset($class_paths[$node_value[0]])) {
             $file_name = $this->generateFilename($class_paths[$node_value[0]]);
             $element->setAttribute('link', $file_name . '#' . $name);
         }
     }
     return $xml;
 }