コード例 #1
0
ファイル: Class.php プロジェクト: rhysr/Docblox
 /**
  * Checks whether the super contains any reference to the existing methods
  * or properties.
  *
  * $super is not a real class, it is an aggregation of all methods and
  * properties in the inheritance tree. This is done because a method may
  * override another method which is not in the direct parent but several
  * levels upwards.
  *
  * To deal with the situation above we flatten every found $sub into
  * the $super. We only store the properties and methods since anything
  * else does not override.
  *
  * The structure of $super is:
  * * methods, array containing `$method_name => array` pairs
  *   * class, name of the deepest leaf where this method is encountered
  *   * object, DOMElement of the method declaration in the deepest leaf
  * * properties, array containing `$property_name => array` pairs
  *   * class, name of the deepest leaf where this property is encountered
  *   * object, DOMElement of the property declaration in the deepest leaf
  *
  * @param array      $super
  * @param string     $class_name Not used; required by the Abstract class
  *
  * @return void
  */
 public function apply(array &$super, $class_name)
 {
     $class_name = current($this->getDirectElementsByTagName($this->node, 'full_name'))->nodeValue;
     // the name is always the first encountered child element with
     // tag name 'name'
     $node_name = $this->getNodeName();
     $parent = current($this->getDirectElementsByTagName($this->node, 'extends'))->nodeValue;
     // only process if the super has a node with this name
     if (isset($super['classes'][$parent])) {
         $docblock = $this->getDocBlockElement();
         /** @var DOMElement $super_object  */
         $super_object = $super['classes'][$parent]['object'];
         /** @var DOMElement $super_docblock  */
         $super_docblock = current($this->getDirectElementsByTagName($super_object, 'docblock'));
         $super_class = current($this->getDirectElementsByTagName($super_object, 'full_name'))->nodeValue;
         // add an element which defines which class' element you override
         $this->node->appendChild(new DOMElement('overrides-from', $super_class));
         $this->copyShortDescription($super_docblock, $docblock);
         $this->copyLongDescription($super_docblock, $docblock);
         $this->copyTags($this->inherited_tags, $super_docblock, $docblock);
     }
     // only add if this has a docblock; otherwise it is useless
     $docblocks = $this->getDirectElementsByTagName($this->node, 'docblock');
     if (count($docblocks) > 0) {
         $super['classes'][$node_name] = array('class' => $class_name, 'object' => $this->node);
     }
     /** @var DOMElement[] $method */
     $methods = $this->getDirectElementsByTagName($this->node, 'method');
     foreach ($methods as $method) {
         $inherit = new DocBlox_Transformer_Behaviour_Inherit_Node_Method($method);
         $inherit->apply($super['methods'], $class_name);
     }
     /** @var DOMElement[] $method */
     $properties = $this->getDirectElementsByTagName($this->node, 'property');
     foreach ($properties as $property) {
         $inherit = new DocBlox_Transformer_Behaviour_Inherit_Node_Property($property);
         $inherit->apply($super['properties'], $class_name);
     }
     // apply inheritance to every class or interface extending this one
     $result = $this->xpath->query('/project/file/*[extends="' . $class_name . '"' . ' or implements="' . $class_name . '"]');
     foreach ($result as $node) {
         $inherit = new DocBlox_Transformer_Behaviour_Inherit_Node_Class($node, $this->xpath);
         $inherit->apply($super, $class_name);
     }
 }
コード例 #2
0
ファイル: Class.php プロジェクト: rvanvelzen/phpDocumentor2
 /**
  * Checks whether the super contains any reference to the existing methods
  * or properties.
  *
  * $super is not a real class, it is an aggregation of all methods and
  * properties in the inheritance tree. This is done because a method may
  * override another method which is not in the direct parent but several
  * levels upwards.
  *
  * To deal with the situation above we flatten every found $sub into
  * the $super. We only store the properties and methods since anything
  * else does not override.
  *
  * The structure of $super is:
  * * methods, array containing `$method_name => array` pairs
  *   * class, name of the deepest leaf where this method is encountered
  *   * object, DOMElement of the method declaration in the deepest leaf
  * * properties, array containing `$property_name => array` pairs
  *   * class, name of the deepest leaf where this property is encountered
  *   * object, DOMElement of the property declaration in the deepest leaf
  *
  * @param array      $super
  * @param string     $class_name Not used; required by the Abstract class
  *
  * @return void
  */
 public function apply(array &$super, $class_name)
 {
     // explicitly make a copy of the super array; every other element should
     // have the $super as reference, except class.
     // When $super is used by reference in this case then other classes will
     // be polluted with methods from sibling classes.
     $super_copy = $super;
     $class_name = current($this->getDirectElementsByTagName($this->node, 'full_name'))->nodeValue;
     // the name is always the first encountered child element with
     // tag name 'name'
     $node_name = $this->getNodeName();
     $parent = current($this->getDirectElementsByTagName($this->node, 'extends'))->nodeValue;
     // only process if the super has a node with this name
     if (isset($super_copy['classes'][$parent])) {
         $docblock = $this->getDocBlockElement();
         /** @var DOMElement $super_object  */
         $super_object = $super_copy['classes'][$parent]['object'];
         /** @var DOMElement $super_docblock  */
         $super_docblock = current($this->getDirectElementsByTagName($super_object, 'docblock'));
         $super_class = current($this->getDirectElementsByTagName($super_object, 'full_name'))->nodeValue;
         // add an element which defines which class' element you override
         $this->node->appendChild(new DOMElement('overrides-from', $super_class));
         if ($super_docblock) {
             $this->copyShortDescription($super_docblock, $docblock);
             $this->copyLongDescription($super_docblock, $docblock);
             $this->copyTags($this->inherited_tags, $super_docblock, $docblock);
         }
     }
     $super_copy['classes'][$node_name] = array('class' => $class_name, 'object' => $this->node);
     /** @var DOMElement[] $method */
     $methods = $this->getDirectElementsByTagName($this->node, 'method');
     $method_names = array();
     foreach ($methods as $method) {
         $method_names[] = $method->getElementsByTagName('name')->item(0)->nodeValue;
         // only process 'real' methods
         if ($method->getAttribute('inherited_from')) {
             continue;
         }
         $inherit = new DocBlox_Transformer_Behaviour_Inherit_Node_Method($method);
         $inherit->apply($super_copy['methods'], $class_name);
     }
     // if a method present in the super classes but it is not declared
     // in this class then add it as an 'inherited_from' method.
     // explicitly do not updates the $super['methods'] array as this is mere
     // a virtual method and not one that counts for inheritance.
     foreach ($super_copy['methods'] as $method_name => $method_collection) {
         // only copy methods that are not overridden and are not private
         if (in_array($method_name, $method_names) || $method_collection['object']->getAttribute('visibility') == 'private') {
             continue;
         }
         // add an element 'inherited_from' to the method itself
         /** @var DOMElement $node */
         $node = clone $method_collection['object'];
         $this->node->appendChild($node);
         $node->appendChild(new DOMElement('inherited_from', $method_collection['class']));
         // get the docblock or create a new one if it doesn't exist
         $docblocks = $node->getElementsByTagName('docblock');
         if ($docblocks->length == 0) {
             $docblock = new DOMElement('docblock');
             $node->appendChild($docblock);
         } else {
             $docblock = $docblocks->item(0);
         }
         // adds a new inherited_from to signify that this method is not
         // declared in this class but inherited from a base class
         $inherited_from_tag = new DOMElement('tag');
         $docblock->appendChild($inherited_from_tag);
         $inherited_from_tag->setAttribute('name', 'inherited_from');
         $inherited_from_tag->setAttribute('refers', $method_collection['class'] . '::' . $method_name . '()');
         $inherited_from_tag->setAttribute('description', $method_collection['class'] . '::' . $method_name . '()');
     }
     /** @var DOMElement[] $method */
     $property_names = array();
     $properties = $this->getDirectElementsByTagName($this->node, 'property');
     foreach ($properties as $property) {
         $property_names[] = $property->getElementsByTagName('name')->item(0)->nodeValue;
         // only process 'real' methods
         if ($property->getAttribute('inherited_from')) {
             continue;
         }
         $inherit = new DocBlox_Transformer_Behaviour_Inherit_Node_Property($property);
         $inherit->apply($super_copy['properties'], $class_name);
     }
     // if a property is present in the super classes but it is not declared
     // in this class then add it as an 'inherited_from' property.
     // explicitly do not updates the $super['properties'] array as this is
     // mere a virtual property and not one that counts for inheritance.
     foreach ($super_copy['properties'] as $property_name => $property_collection) {
         // only copy methods that are not overridden and are not private
         if (in_array($property_name, $property_names) || $property_collection['object']->getAttribute('visibility') == 'private') {
             continue;
         }
         // add an element 'inherited_from' to the method itself
         /** @var DOMElement $node */
         $node = clone $property_collection['object'];
         $this->node->appendChild($node);
         $node->appendChild(new DOMElement('inherited_from', $property_collection['class']));
         // get the docblock or create a new one if it doesn't exist
         $docblocks = $node->getElementsByTagName('docblock');
         if ($docblocks->length == 0) {
             $docblock = new DOMElement('docblock');
             $node->appendChild($docblock);
         } else {
             $docblock = $docblocks->item(0);
         }
         // adds a new inherited_from to signify that this method is not
         // declared in this class but inherited from a base class
         $inherited_from_tag = new DOMElement('tag');
         $docblock->appendChild($inherited_from_tag);
         $inherited_from_tag->setAttribute('name', 'inherited_from');
         $inherited_from_tag->setAttribute('refers', $property_collection['class'] . '::' . $property_name);
         $inherited_from_tag->setAttribute('description', $property_collection['class'] . '::' . $property_name);
     }
     // apply inheritance to every class or interface extending this one
     $xpath = new DOMXPath($this->document);
     $result = $xpath->query('/project/file/*[extends="' . $class_name . '"' . ' or implements="' . $class_name . '"]');
     foreach ($result as $node) {
         $child_class_name = $node->getElementsByTagName('full_name')->item(0)->nodeValue;
         if (!$child_class_name) {
             throw new Exception('A class was encountered with no FQCN. This should not ' . 'happen; please contact the DocBlox developers to have them ' . 'analyze this issue');
         }
         $inherit = new DocBlox_Transformer_Behaviour_Inherit_Node_Class($node, $this->document);
         $inherit->apply($super_copy, $class_name);
     }
 }
コード例 #3
0
ファイル: Inherit.php プロジェクト: rvanvelzen/phpDocumentor2
 /**
  * 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)
 {
     $this->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, $xml);
         $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, $xml);
         $methods = array();
         // shut up operator is necessary to silence autoloaders
         $parent_class_name = $node->getElementsByTagName('extends')->item(0)->nodeValue;
         if (@class_exists($parent_class_name)) {
             $refl = new ReflectionClass($parent_class_name);
             /** @var ReflectionMethod $method */
             foreach ($refl->getMethods() as $method) {
                 if ($method->isPrivate()) {
                     continue;
                 }
                 $node_name = new DOMElement('name', $method->getName());
                 $method_node = $xml->createElement('method');
                 $method_node->appendChild($node_name);
                 $method_node->setAttribute('final', $method->isFinal() ? 'true' : 'false');
                 $method_node->setAttribute('abstract', $method->isAbstract() ? 'true' : 'false');
                 $method_node->setAttribute('static', $method->isStatic() ? 'true' : 'false');
                 $method_node->setAttribute('visibility', $method->isPublic() ? 'public' : 'protected');
                 $methods[$method->getName()] = array('class' => $parent_class_name, 'object' => $method_node);
             }
         }
         $super = array('classes' => array(), 'properties' => array(), 'methods' => $methods);
         $inherit->apply($super, null);
     }
     return $xml;
 }
コード例 #4
0
ファイル: Inherit.php プロジェクト: rhysr/Docblox
 /**
  * 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;
 }