ApiController.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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\commands;
  8. use yii\apidoc\components\BaseController;
  9. use yii\apidoc\models\Context;
  10. use yii\apidoc\renderers\ApiRenderer;
  11. use yii\helpers\ArrayHelper;
  12. use yii\helpers\Console;
  13. use yii\helpers\FileHelper;
  14. /**
  15. * Generate class API documentation.
  16. *
  17. * @author Carsten Brandt <mail@cebe.cc>
  18. * @since 2.0
  19. */
  20. class ApiController extends BaseController
  21. {
  22. /**
  23. * @var string url to where the guide files are located
  24. */
  25. public $guide;
  26. /**
  27. * @var string prefix to prepend to all guide file names.
  28. */
  29. public $guidePrefix = 'guide-';
  30. // TODO add force update option
  31. /**
  32. * Renders API documentation files
  33. * @param array $sourceDirs
  34. * @param string $targetDir
  35. * @return int
  36. */
  37. public function actionIndex(array $sourceDirs, $targetDir)
  38. {
  39. $renderer = $this->findRenderer($this->template);
  40. $targetDir = $this->normalizeTargetDir($targetDir);
  41. if ($targetDir === false || $renderer === false) {
  42. return 1;
  43. }
  44. $renderer->apiUrl = './';
  45. $renderer->guidePrefix = $this->guidePrefix;
  46. if ($this->pageTitle !== null) {
  47. $renderer->pageTitle = $this->pageTitle;
  48. }
  49. // setup reference to guide
  50. if ($this->guide !== null) {
  51. $renderer->guideUrl = $guideUrl = $this->guide;
  52. } else {
  53. $guideUrl = './';
  54. $renderer->guideUrl = $targetDir;
  55. if (file_exists($renderer->generateGuideUrl('README.md'))) {
  56. $renderer->guideUrl = $guideUrl;
  57. } else {
  58. $renderer->guideUrl = null;
  59. }
  60. }
  61. // search for files to process
  62. if (($files = $this->searchFiles($sourceDirs)) === false) {
  63. return 1;
  64. }
  65. // load context from cache
  66. $context = $this->loadContext($targetDir);
  67. $this->stdout('Checking for updated files... ');
  68. foreach ($context->files as $file => $sha) {
  69. if (!file_exists($file)) {
  70. $this->stdout('At least one file has been removed. Rebuilding the context...');
  71. $context = new Context();
  72. if (($files = $this->searchFiles($sourceDirs)) === false) {
  73. return 1;
  74. }
  75. break;
  76. }
  77. if (sha1_file($file) === $sha) {
  78. unset($files[$file]);
  79. }
  80. }
  81. $this->stdout('done.' . PHP_EOL, Console::FG_GREEN);
  82. // process files
  83. $fileCount = count($files);
  84. $this->stdout($fileCount . ' file' . ($fileCount == 1 ? '' : 's') . ' to update.' . PHP_EOL);
  85. Console::startProgress(0, $fileCount, 'Processing files... ', false);
  86. $done = 0;
  87. foreach ($files as $file) {
  88. $context->addFile($file);
  89. Console::updateProgress(++$done, $fileCount);
  90. }
  91. Console::endProgress(true);
  92. $this->stdout('done.' . PHP_EOL, Console::FG_GREEN);
  93. // save processed data to cache
  94. $this->storeContext($context, $targetDir);
  95. $this->updateContext($context);
  96. // render models
  97. $renderer->controller = $this;
  98. $renderer->render($context, $targetDir);
  99. if (!empty($context->errors)) {
  100. ArrayHelper::multisort($context->errors, 'file');
  101. file_put_contents($targetDir . '/errors.txt', print_r($context->errors, true));
  102. $this->stdout(count($context->errors) . " errors have been logged to $targetDir/errors.txt\n", Console::FG_RED, Console::BOLD);
  103. }
  104. if (!empty($context->warnings)) {
  105. ArrayHelper::multisort($context->warnings, 'file');
  106. file_put_contents($targetDir . '/warnings.txt', print_r($context->warnings, true));
  107. $this->stdout(count($context->warnings) . " warnings have been logged to $targetDir/warnings.txt\n", Console::FG_YELLOW, Console::BOLD);
  108. }
  109. }
  110. /**
  111. * @inheritdoc
  112. */
  113. protected function findFiles($path, $except = [])
  114. {
  115. if (empty($except)) {
  116. $except = ['vendor/', 'tests/'];
  117. }
  118. $path = FileHelper::normalizePath($path);
  119. $options = [
  120. 'filter' => function ($path) {
  121. if (is_file($path)) {
  122. $file = basename($path);
  123. if ($file[0] < 'A' || $file[0] > 'Z') {
  124. return false;
  125. }
  126. }
  127. return null;
  128. },
  129. 'only' => ['*.php'],
  130. 'except' => $except,
  131. ];
  132. return FileHelper::findFiles($path, $options);
  133. }
  134. /**
  135. * @inheritdoc
  136. * @return ApiRenderer
  137. */
  138. protected function findRenderer($template)
  139. {
  140. // find renderer by class name
  141. if (class_exists($template)) {
  142. return new $template();
  143. }
  144. $rendererClass = 'yii\\apidoc\\templates\\' . $template . '\\ApiRenderer';
  145. if (!class_exists($rendererClass)) {
  146. $this->stderr('Renderer not found.' . PHP_EOL);
  147. return false;
  148. }
  149. return new $rendererClass();
  150. }
  151. /**
  152. * @inheritdoc
  153. */
  154. public function options($actionID)
  155. {
  156. return array_merge(parent::options($actionID), ['guide', 'guidePrefix']);
  157. }
  158. }