/src/DocBlox/Plugin/Core/Transformer/Behaviour/Tag/Uses.php

https://github.com/studioskylab/Docblox · PHP · 175 lines · 99 code · 21 blank · 55 comment · 18 complexity · 977aecf69d07ec8e8f23400db0a7367a MD5 · raw file

  1. <?php
  2. /**
  3. * DocBlox
  4. *
  5. * PHP 5
  6. *
  7. * @category DocBlox
  8. * @package Transformer
  9. * @subpackage Behaviour
  10. * @author Mike van Riel <mike.vanriel@naenius.com>
  11. * @license http://www.opensource.org/licenses/mit-license.php MIT
  12. * @link http://docblox-project.org
  13. */
  14. /**
  15. * Behaviour that adds support for the @uses tag
  16. *
  17. * @category DocBlox
  18. * @package Transformer
  19. * @subpackage Behaviour
  20. * @author Mike van Riel <mike.vanriel@naenius.com>
  21. * @license http://www.opensource.org/licenses/mit-license.php MIT
  22. * @link http://docblox-project.org
  23. */
  24. class DocBlox_Plugin_Core_Transformer_Behaviour_Tag_Uses extends
  25. DocBlox_Transformer_Behaviour_Abstract
  26. {
  27. /**
  28. * Find all return tags that contain 'self' or '$this' and replace those
  29. * terms for the name of the current class' type.
  30. *
  31. * @param DOMDocument $xml
  32. *
  33. * @todo split method into submethods
  34. *
  35. * @return DOMDocument
  36. */
  37. public function process(DOMDocument $xml)
  38. {
  39. $xpath = new DOMXPath($xml);
  40. $nodes = $xpath->query('//tag[@name=\'uses\']');
  41. /** @var DOMElement $node */
  42. foreach($nodes as $node) {
  43. $refers = $node->getAttribute('refers');
  44. $refers_array = explode('::', $refers);
  45. // determine the type so we know where to put the @usedby tag on
  46. $type = 'class';
  47. if (isset($refers_array[1]))
  48. {
  49. // starts with $ = property, ends with () = method,
  50. // otherwise constant
  51. $type = $refers_array[1][0] == '$' ? 'property' : 'constant';
  52. $type = substr($refers_array[1], -2) == '()' ? 'method' : $type;
  53. }
  54. switch($type)
  55. {
  56. case 'class':
  57. // escape single quotes in the class name
  58. $xpath_refers = 'concat(\''.str_replace(
  59. array("'", '"'),
  60. array('\', "\'", \'', '\', \'"\' , \''),
  61. $refers
  62. ) . "', '')";
  63. $qry = '/project/file/class[full_name=' . $xpath_refers . ']';
  64. break;
  65. default:
  66. $class_name = $refers_array[0];
  67. // escape single quotes in the class name
  68. $xpath_class_name = 'concat(\''.str_replace(
  69. array("'", '"'),
  70. array('\', "\'", \'', '\', \'"\' , \''),
  71. $class_name
  72. ) . "', '')";
  73. // escape single quotes in the method name
  74. $xpath_method_name = 'concat(\''.str_replace(
  75. array("'", '"'),
  76. array('\', "\'", \'', '\', \'"\' , \''),
  77. rtrim($refers_array[1], '()')
  78. ) . "', '')";
  79. $qry = '/project/file/class[full_name=' . $xpath_class_name
  80. . ']/'.$type.'[name=' . $xpath_method_name .']';
  81. break;
  82. }
  83. // get the nodes; we are unable to work around the
  84. // shut up operator as there is no pre-validation possible.
  85. $referral_nodes = @$xpath->query($qry);
  86. // if the query is wrong; output a Critical error and continue to
  87. // the next @uses
  88. if($referral_nodes === false) {
  89. $this->log(
  90. 'An XPath error occurs while processing @uses, '
  91. . 'the query used was: ' . $qry, DocBlox_Core_Log::CRIT
  92. );
  93. continue;
  94. }
  95. // check if the result is unique; if not we error and continue
  96. // to the next @uses
  97. if ($referral_nodes->length > 1) {
  98. $this->log(
  99. '@uses "'.$refers.'" refers to more than 1 element',
  100. DocBlox_Core_Log::ERR
  101. );
  102. continue;
  103. }
  104. // if there is one matching element; link them together
  105. if ($referral_nodes->length > 0) {
  106. $referral = $referral_nodes->item(0);
  107. $docblock = $referral->getElementsByTagName('docblock');
  108. if ($docblock->length < 1) {
  109. $docblock = new DOMElement('docblock');
  110. $referral->appendChild($docblock);
  111. } else {
  112. $docblock = $docblock->item(0);
  113. }
  114. $used_by = new DOMElement('tag');
  115. $docblock->appendChild($used_by);
  116. $used_by->setAttribute('name', 'used_by');
  117. $used_by->setAttribute('line', '');
  118. // gather the name of the referring element and set that as refers
  119. // attribute
  120. if ($node->parentNode->parentNode->nodeName == 'class') {
  121. // if the element where the @uses is in is a class; nothing
  122. // more than the class name need to returned
  123. $referral_name = $node->parentNode->parentNode
  124. ->getElementsByTagName('full_name')->item(0)->nodeValue;
  125. } else {
  126. $referral_class_name = null;
  127. if ($node->parentNode->parentNode->nodeName == 'method') {
  128. // gather the name of the class where the @uses is in
  129. $referral_class_name = $node->parentNode->parentNode
  130. ->parentNode->getElementsByTagName('full_name')->item(0)
  131. ->nodeValue;
  132. }
  133. // gather the name of the subelement of the class where
  134. // the @uses is in
  135. $referral_name = $node->parentNode->parentNode
  136. ->getElementsByTagName('name')->item(0)->nodeValue;
  137. // if it is a method; suffix with ()
  138. if ($node->parentNode->parentNode->nodeName == 'method'
  139. || $node->parentNode->parentNode->nodeName == 'function'
  140. ) {
  141. $referral_name .= '()';
  142. }
  143. // only prefix class name if this is a class member
  144. if ($referral_class_name) {
  145. $referral_name = $referral_class_name . '::' . $referral_name;
  146. }
  147. }
  148. $used_by->setAttribute('description', $referral_name);
  149. $used_by->setAttribute('refers', $referral_name);
  150. }
  151. }
  152. return $xml;
  153. }
  154. }