BaseRenderer.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\apidoc\renderers;
  8. use Yii;
  9. use yii\apidoc\helpers\ApiMarkdown;
  10. use yii\apidoc\helpers\ApiMarkdownLaTeX;
  11. use yii\apidoc\models\BaseDoc;
  12. use yii\apidoc\models\ClassDoc;
  13. use yii\apidoc\models\ConstDoc;
  14. use yii\apidoc\models\Context;
  15. use yii\apidoc\models\EventDoc;
  16. use yii\apidoc\models\InterfaceDoc;
  17. use yii\apidoc\models\MethodDoc;
  18. use yii\apidoc\models\PropertyDoc;
  19. use yii\apidoc\models\TraitDoc;
  20. use yii\apidoc\models\TypeDoc;
  21. use yii\base\Component;
  22. use yii\console\Controller;
  23. /**
  24. * Base class for all documentation renderers
  25. *
  26. * @author Carsten Brandt <mail@cebe.cc>
  27. * @since 2.0
  28. */
  29. abstract class BaseRenderer extends Component
  30. {
  31. /**
  32. * @deprecated since 2.0.1 use [[$guidePrefix]] instead which allows configuring this options
  33. */
  34. const GUIDE_PREFIX = 'guide-';
  35. public $guidePrefix = 'guide-';
  36. public $apiUrl;
  37. /**
  38. * @var string string to use as the title of the generated page.
  39. */
  40. public $pageTitle;
  41. /**
  42. * @var Context the [[Context]] currently being rendered.
  43. */
  44. public $apiContext;
  45. /**
  46. * @var Controller the apidoc controller instance. Can be used to control output.
  47. */
  48. public $controller;
  49. public $guideUrl;
  50. public function init()
  51. {
  52. ApiMarkdown::$renderer = $this;
  53. ApiMarkdownLaTeX::$renderer = $this;
  54. }
  55. /**
  56. * creates a link to a type (class, interface or trait)
  57. * @param ClassDoc|InterfaceDoc|TraitDoc|ClassDoc[]|InterfaceDoc[]|TraitDoc[]|string|string[] $types
  58. * @param string $title a title to be used for the link TODO check whether [[yii\...|Class]] is supported
  59. * @param BaseDoc $context
  60. * @param array $options additional HTML attributes for the link.
  61. * @return string
  62. */
  63. public function createTypeLink($types, $context = null, $title = null, $options = [])
  64. {
  65. if (!is_array($types)) {
  66. $types = [$types];
  67. }
  68. if (count($types) > 1) {
  69. $title = null;
  70. }
  71. $links = [];
  72. foreach ($types as $type) {
  73. $postfix = '';
  74. if (is_string($type)) {
  75. if (!empty($type) && substr_compare($type, '[]', -2, 2) === 0) {
  76. $postfix = '[]';
  77. $type = substr($type, 0, -2);
  78. }
  79. if ($type === '$this' && $context instanceof TypeDoc) {
  80. $title = '$this';
  81. $type = $context;
  82. } elseif (($t = $this->apiContext->getType(ltrim($type, '\\'))) !== null) {
  83. $type = $t;
  84. } elseif (!empty($type) && $type[0] !== '\\' && ($t = $this->apiContext->getType($this->resolveNamespace($context) . '\\' . ltrim($type, '\\'))) !== null) {
  85. $type = $t;
  86. } else {
  87. ltrim($type, '\\');
  88. }
  89. }
  90. if (is_string($type)) {
  91. $linkText = ltrim($type, '\\');
  92. if ($title !== null) {
  93. $linkText = $title;
  94. $title = null;
  95. }
  96. $phpTypes = [
  97. 'callable',
  98. 'array',
  99. 'string',
  100. 'boolean',
  101. 'bool',
  102. 'integer',
  103. 'int',
  104. 'float',
  105. 'object',
  106. 'resource',
  107. 'null',
  108. 'false',
  109. 'true',
  110. ];
  111. $phpTypeAliases = [
  112. 'true' => 'boolean',
  113. 'false' => 'boolean',
  114. 'bool' => 'boolean',
  115. 'int' => 'integer',
  116. ];
  117. $phpTypeDisplayAliases = [
  118. 'bool' => 'boolean',
  119. 'int' => 'integer',
  120. ];
  121. // check if it is PHP internal class
  122. if (((class_exists($type, false) || interface_exists($type, false) || trait_exists($type, false)) &&
  123. ($reflection = new \ReflectionClass($type)) && $reflection->isInternal())) {
  124. $links[] = $this->generateLink($linkText, 'http://www.php.net/class.' . strtolower(ltrim($type, '\\')), $options) . $postfix;
  125. } elseif (in_array($type, $phpTypes)) {
  126. if (isset($phpTypeDisplayAliases[$type])) {
  127. $linkText = $phpTypeDisplayAliases[$type];
  128. }
  129. if (isset($phpTypeAliases[$type])) {
  130. $type = $phpTypeAliases[$type];
  131. }
  132. $links[] = $this->generateLink($linkText, 'http://www.php.net/language.types.' . strtolower(ltrim($type, '\\')), $options) . $postfix;
  133. } else {
  134. $links[] = $type . $postfix;
  135. }
  136. } elseif ($type instanceof BaseDoc) {
  137. $linkText = $type->name;
  138. if ($title !== null) {
  139. $linkText = $title;
  140. $title = null;
  141. }
  142. $links[] = $this->generateLink($linkText, $this->generateApiUrl($type->name), $options) . $postfix;
  143. }
  144. }
  145. return implode('|', $links);
  146. }
  147. /**
  148. * creates a link to a subject
  149. * @param PropertyDoc|MethodDoc|ConstDoc|EventDoc $subject
  150. * @param string $title
  151. * @param array $options additional HTML attributes for the link.
  152. * @return string
  153. */
  154. public function createSubjectLink($subject, $title = null, $options = [])
  155. {
  156. if ($title === null) {
  157. if ($subject instanceof MethodDoc) {
  158. $title = $subject->name . '()';
  159. } else {
  160. $title = $subject->name;
  161. }
  162. }
  163. if (($type = $this->apiContext->getType($subject->definedBy)) === null) {
  164. return $subject->name;
  165. } else {
  166. $link = $this->generateApiUrl($type->name);
  167. if ($subject instanceof MethodDoc) {
  168. $link .= '#' . $subject->name . '()';
  169. } else {
  170. $link .= '#' . $subject->name;
  171. }
  172. $link .= '-detail';
  173. return $this->generateLink($title, $link, $options);
  174. }
  175. }
  176. /**
  177. * @param BaseDoc|string $context
  178. * @return string
  179. */
  180. private function resolveNamespace($context)
  181. {
  182. // TODO use phpdoc Context for this
  183. if ($context === null) {
  184. return '';
  185. }
  186. if ($context instanceof TypeDoc) {
  187. return $context->namespace;
  188. }
  189. if ($context->hasProperty('definedBy')) {
  190. $type = $this->apiContext->getType($context);
  191. if ($type !== null) {
  192. return $type->namespace;
  193. }
  194. }
  195. return '';
  196. }
  197. /**
  198. * generate link markup
  199. * @param $text
  200. * @param $href
  201. * @param array $options additional HTML attributes for the link.
  202. * @return mixed
  203. */
  204. abstract protected function generateLink($text, $href, $options = []);
  205. /**
  206. * Generate an url to a type in apidocs
  207. * @param $typeName
  208. * @return mixed
  209. */
  210. abstract public function generateApiUrl($typeName);
  211. /**
  212. * Generate an url to a guide page
  213. * @param string $file
  214. * @return string
  215. */
  216. public function generateGuideUrl($file)
  217. {
  218. //skip parsing external url
  219. if ( (strpos($file, 'https://') !== false) || (strpos($file, 'http://') !== false) ) {
  220. return $file;
  221. }
  222. $hash = '';
  223. if (($pos = strpos($file, '#')) !== false) {
  224. $hash = substr($file, $pos);
  225. $file = substr($file, 0, $pos);
  226. }
  227. return rtrim($this->guideUrl, '/') . '/' . $this->guidePrefix . basename($file, '.md') . '.html' . $hash;
  228. }
  229. }