PageRenderTime 40ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/DocBlox/Transformer/Behaviour/Inherit/Node/Class.php

https://github.com/androa/Docblox
PHP | 170 lines | 76 code | 20 blank | 74 comment | 2 complexity | cff36115f9346b3fff029fabacd230fb MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * DocBlox
  4. *
  5. * PHP Version 5
  6. *
  7. * @category DocBlox
  8. * @package Transformer
  9. * @subpackage Behaviour
  10. * @author Mike van Riel <mike.vanriel@naenius.com>
  11. * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com)
  12. * @license http://www.opensource.org/licenses/mit-license.php MIT
  13. * @link http://docblox-project.org
  14. */
  15. /**
  16. * Responsible for adding inheritance behaviour to an individual class.
  17. *
  18. * @category DocBlox
  19. * @package Transformer
  20. * @subpackage Behaviour
  21. * @author Mike van Riel <mike.vanriel@naenius.com>
  22. * @license http://www.opensource.org/licenses/mit-license.php MIT
  23. * @link http://docblox-project.org
  24. */
  25. class DocBlox_Transformer_Behaviour_Inherit_Node_Class extends
  26. DocBlox_Transformer_Behaviour_Inherit_Node_Abstract
  27. {
  28. /**
  29. * @var DOMXPath
  30. */
  31. protected $xpath = null;
  32. /** @var string[] All class tags that are inherited when none are defined */
  33. protected $inherited_tags = array(
  34. 'package',
  35. 'subpackage',
  36. 'version',
  37. 'copyright',
  38. 'author'
  39. );
  40. /**
  41. * Initializes this node and registers the XPath object.
  42. *
  43. * @param DOMElement $node
  44. * @param DOMXPath $xpath
  45. */
  46. public function __construct(DOMElement $node, DOMXPath $xpath)
  47. {
  48. parent::__construct($node);
  49. $this->xpath = $xpath;
  50. }
  51. /**
  52. * Returns the name of the given class or interface node.
  53. *
  54. * @return string
  55. */
  56. protected function getNodeName()
  57. {
  58. return current(
  59. $this->getDirectElementsByTagName($this->node, 'full_name')
  60. )->nodeValue;
  61. }
  62. /**
  63. * Checks whether the super contains any reference to the existing methods
  64. * or properties.
  65. *
  66. * $super is not a real class, it is an aggregation of all methods and
  67. * properties in the inheritance tree. This is done because a method may
  68. * override another method which is not in the direct parent but several
  69. * levels upwards.
  70. *
  71. * To deal with the situation above we flatten every found $sub into
  72. * the $super. We only store the properties and methods since anything
  73. * else does not override.
  74. *
  75. * The structure of $super is:
  76. * * methods, array containing `$method_name => array` pairs
  77. * * class, name of the deepest leaf where this method is encountered
  78. * * object, DOMElement of the method declaration in the deepest leaf
  79. * * properties, array containing `$property_name => array` pairs
  80. * * class, name of the deepest leaf where this property is encountered
  81. * * object, DOMElement of the property declaration in the deepest leaf
  82. *
  83. * @param array $super
  84. * @param string $class_name Not used; required by the Abstract class
  85. *
  86. * @return void
  87. */
  88. public function apply(array &$super, $class_name)
  89. {
  90. $class_name = current(
  91. $this->getDirectElementsByTagName($this->node, 'full_name')
  92. )->nodeValue;
  93. // the name is always the first encountered child element with
  94. // tag name 'name'
  95. $node_name = $this->getNodeName();
  96. $parent = current(
  97. $this->getDirectElementsByTagName($this->node, 'extends')
  98. )->nodeValue;
  99. // only process if the super has a node with this name
  100. if (isset($super['classes'][$parent])) {
  101. $docblock = $this->getDocBlockElement();
  102. /** @var DOMElement $super_object */
  103. $super_object = $super['classes'][$parent]['object'];
  104. /** @var DOMElement $super_docblock */
  105. $super_docblock = current(
  106. $this->getDirectElementsByTagName($super_object, 'docblock')
  107. );
  108. $super_class = current(
  109. $this->getDirectElementsByTagName($super_object, 'full_name')
  110. )->nodeValue;
  111. // add an element which defines which class' element you override
  112. $this->node->appendChild(new DOMElement('overrides-from', $super_class));
  113. $this->copyShortDescription($super_docblock, $docblock);
  114. $this->copyLongDescription($super_docblock, $docblock);
  115. $this->copyTags($this->inherited_tags, $super_docblock, $docblock);
  116. }
  117. // only add if this has a docblock; otherwise it is useless
  118. $docblocks = $this->getDirectElementsByTagName($this->node, 'docblock');
  119. if (count($docblocks) > 0) {
  120. $super['classes'][$node_name] = array(
  121. 'class' => $class_name,
  122. 'object' => $this->node
  123. );
  124. }
  125. /** @var DOMElement[] $method */
  126. $methods = $this->getDirectElementsByTagName($this->node, 'method');
  127. foreach ($methods as $method) {
  128. $inherit = new DocBlox_Transformer_Behaviour_Inherit_Node_Method($method);
  129. $inherit->apply($super['methods'], $class_name);
  130. }
  131. /** @var DOMElement[] $method */
  132. $properties = $this->getDirectElementsByTagName($this->node, 'property');
  133. foreach ($properties as $property) {
  134. $inherit = new DocBlox_Transformer_Behaviour_Inherit_Node_Property($property);
  135. $inherit->apply($super['properties'], $class_name);
  136. }
  137. // apply inheritance to every class or interface extending this one
  138. $result = $this->xpath->query(
  139. '/project/file/*[extends="' . $class_name . '"'
  140. . ' or implements="' . $class_name . '"]'
  141. );
  142. foreach ($result as $node)
  143. {
  144. $inherit = new DocBlox_Transformer_Behaviour_Inherit_Node_Class(
  145. $node, $this->xpath
  146. );
  147. $inherit->apply($super, $class_name);
  148. }
  149. }
  150. }