Commit 023f4d0a by Carsten Brandt

refactored apidoc extensions completely.

separated guide and apidoc, better maintainability
parent 683a46d9
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* @author Carsten Brandt <mail@cebe.cc>
*/
namespace yii\apidoc\commands;
use phpDocumentor\Reflection\FileReflector;
use TokenReflection\ReflectionFile;
use yii\apidoc\templates\BaseRenderer;
use yii\console\Controller;
use yii\apidoc\renderers\ApiRenderer;
use yii\helpers\ArrayHelper;
use yii\helpers\Console;
use yii\helpers\FileHelper;
use yii\apidoc\components\OfflineRenderer;
use yii\apidoc\models\Context;
use Yii;
/**
* Command to render API Documentation files
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class RenderController extends Controller
class ApiController extends BaseController
{
public $template = 'bootstrap';
/**
* @var string url to where the guide files are located
*/
public $guide;
// TODO add force update option
/**
* Renders API documentation files
* @param array $sourceDirs
......@@ -38,47 +28,23 @@ class RenderController extends Controller
*/
public function actionIndex(array $sourceDirs, $targetDir)
{
$targetDir = rtrim(Yii::getAlias($targetDir), '\\/');
if (is_dir($targetDir) && !$this->confirm('TargetDirectory already exists. Overwrite?')) {
return 2;
}
if (!is_dir($targetDir)) {
mkdir($targetDir);
}
$renderer = $this->findRenderer();
if ($renderer === false) {
$renderer = $this->findRenderer($this->template);
$targetDir = $this->normalizeTargetDir($targetDir);
if ($targetDir === false || $renderer === false) {
return 1;
}
$renderer->targetDir = $targetDir;
if ($this->guide !== null && $renderer->hasProperty('guideUrl')) {
$renderer->guideUrl = './';
$renderer->markDownFiles = $this->findMarkdownFiles($this->guide, ['README.md']);
}
$this->stdout('Searching files to process... ');
$files = [];
foreach($sourceDirs as $source) {
foreach($this->findFiles($source) as $fileName) {
$files[$fileName] = $fileName;
}
}
$this->stdout('done.' . PHP_EOL, Console::FG_GREEN);
if (empty($files)) {
$this->stderr('Error: No php files found to process.' . PHP_EOL);
return 1;
// setup reference to guide
if ($this->guide !== null) {
$renderer->guideUrl = $this->guide;
$renderer->guideReferences = []; // TODO set references
}
$context = new Context();
$cacheFile = $targetDir . '/cache/' . md5(serialize($files)) . '.tmp';
if (file_exists($cacheFile)) {
$this->stdout('Loading processed data from cache... ');
$context = unserialize(file_get_contents($cacheFile));
$this->stdout('done.' . PHP_EOL, Console::FG_GREEN);
// search for files to process
$files = $this->searchFiles($sourceDirs);
// load context from cache
$context = $this->loadContext($targetDir);
$this->stdout('Checking for updated files... ');
foreach($context->files as $file => $sha) {
if (sha1_file($file) === $sha) {
......@@ -86,8 +52,8 @@ class RenderController extends Controller
}
}
$this->stdout('done.' . PHP_EOL, Console::FG_GREEN);
}
// process files
$fileCount = count($files);
$this->stdout($fileCount . ' file' . ($fileCount == 1 ? '' : 's') . ' to update.' . PHP_EOL);
Console::startProgress(0, $fileCount, 'Processing files... ', false);
......@@ -100,42 +66,16 @@ class RenderController extends Controller
$this->stdout('done.' . PHP_EOL, Console::FG_GREEN);
// save processed data to cache
if (!is_dir(dirname($cacheFile))) {
mkdir(dirname($cacheFile));
}
file_put_contents($cacheFile, serialize($context));
$this->storeContext($context, $targetDir);
$this->stdout('Updating cross references and backlinks... ');
$context->updateReferences();
$this->stdout('done.' . PHP_EOL, Console::FG_GREEN);
$this->updateContext($context);
// render models
$renderer->renderApi($context, $this);
$renderer->controller = $this;
$renderer->render($context, $targetDir);
ArrayHelper::multisort($context->errors, 'file');
print_r($context->errors);
// render guide if specified
if ($this->guide !== null) {
$renderer->renderMarkdownFiles($this);
$this->stdout('Publishing images...');
FileHelper::copyDirectory(rtrim($this->guide, '/\\') . '/images', $targetDir . '/images');
$this->stdout('done.' . PHP_EOL, Console::FG_GREEN);
}
}
/**
* @return BaseRenderer
*/
protected function findRenderer()
{
$rendererClass = 'yii\\apidoc\\templates\\' . $this->template . '\\Renderer';
if (!class_exists($rendererClass)) {
$this->stderr('Renderer not found.' . PHP_EOL);
return false;
}
return new $rendererClass();
}
protected function findFiles($path, $except = ['vendor/', 'tests/'])
......@@ -157,14 +97,17 @@ class RenderController extends Controller
return FileHelper::findFiles($path, $options);
}
protected function findMarkdownFiles($path, $except = [])
/**
* @return ApiRenderer
*/
protected function findRenderer($template)
{
$path = FileHelper::normalizePath($path);
$options = [
'only' => ['*.md'],
'except' => $except,
];
return FileHelper::findFiles($path, $options);
$rendererClass = 'yii\\apidoc\\templates\\' . $template . '\\ApiRenderer';
if (!class_exists($rendererClass)) {
$this->stderr('Renderer not found.' . PHP_EOL);
return false;
}
return new $rendererClass();
}
/**
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\apidoc\commands;
use yii\apidoc\renderers\BaseRenderer;
use yii\console\Controller;
use yii\helpers\Console;
use yii\apidoc\models\Context;
use Yii;
/**
* Command to render API Documentation files
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
abstract class BaseController extends Controller
{
/**
* @var string template to use for rendering
*/
public $template = 'bootstrap';
/**
* @var string|array files to exclude. NOT IMPLEMENTED YET
*/
public $exclude; // TODO implement
protected function normalizeTargetDir($target)
{
$target = rtrim(Yii::getAlias($target), '\\/');
if (file_exists($target)) {
if (is_dir($target) && !$this->confirm('TargetDirectory already exists. Overwrite?')) {
$this->stderr('User aborted.' . PHP_EOL);
return false;
}
if (is_file($target)) {
$this->stderr("Error: Target directory \"$target\" is a file!" . PHP_EOL);
return false;
}
} else {
mkdir($target, 0777, true);
}
return $target;
}
protected function searchFiles($sourceDirs)
{
$this->stdout('Searching files to process... ');
$files = [];
foreach($sourceDirs as $source) {
foreach($this->findFiles($source) as $fileName) {
$files[$fileName] = $fileName;
}
}
$this->stdout('done.' . PHP_EOL, Console::FG_GREEN);
if (empty($files)) {
$this->stderr('Error: No files found to process.' . PHP_EOL);
return 1;
}
return $files;
}
protected abstract function findFiles($dir);
protected function loadContext($location)
{
$context = new Context();
$cacheFile = $location . '/cache/apidoc.data';
$this->stdout('Loading apidoc data from cache... ');
if (file_exists($cacheFile)) {
$context = unserialize(file_get_contents($cacheFile));
$this->stdout('done.' . PHP_EOL, Console::FG_GREEN);
} else {
$this->stdout('no data available.' . PHP_EOL, Console::FG_YELLOW);
}
return $context;
}
protected function storeContext($context, $location)
{
$cacheFile = $location . '/cache/apidoc.data';
if (!is_dir($dir = dirname($cacheFile))) {
mkdir($dir, 0777, true);
}
file_put_contents($cacheFile, serialize($context));
}
/**
* @param Context $context
*/
protected function updateContext($context)
{
$this->stdout('Updating cross references and backlinks... ');
$context->updateReferences();
$this->stdout('done.' . PHP_EOL, Console::FG_GREEN);
}
/**
* @return BaseRenderer
*/
protected abstract function findRenderer($template);
/**
* @inheritdoc
*/
public function globalOptions()
{
return array_merge(parent::globalOptions(), ['template', 'exclude']);
}
}
<?php
/**
* @author Carsten Brandt <mail@cebe.cc>
*/
namespace yii\apidoc\commands;
use yii\apidoc\models\Context;
use yii\apidoc\renderers\BaseRenderer;
use yii\apidoc\renderers\GuideRenderer;
use yii\helpers\Console;
use yii\helpers\FileHelper;
use Yii;
/**
* This command can render documentation stored as markdown files such as the yii guide
* or your own applications documentation setup.
*
*/
class GuideController extends BaseController
{
/**
* @var string path or URL to the api docs to allow links to classes and properties/methods.
*/
public $apiDocs;
/**
* Renders API documentation files
* @param array $sourceDirs
* @param string $targetDir
* @return int
*/
public function actionIndex(array $sourceDirs, $targetDir)
{
$renderer = $this->findRenderer($this->template);
$targetDir = $this->normalizeTargetDir($targetDir);
if ($targetDir === false || $renderer === false) {
return 1;
}
// setup reference to apidoc
if ($this->apiDocs !== null) {
$renderer->apiUrl = $this->apiDocs;
$renderer->apiContext = $this->loadContext($this->apiDocs);
$this->updateContext($renderer->apiContext); // TODO autodetect API docs in same folder
} else {
$renderer->apiContext = new Context();
}
// search for files to process
$files = $this->searchFiles($sourceDirs);
$renderer->controller = $this;
$renderer->render($files, $targetDir);
$this->stdout('Publishing images...');
foreach($sourceDirs as $source) {
FileHelper::copyDirectory(rtrim($source, '/\\') . '/images', $targetDir . '/images');
}
$this->stdout('done.' . PHP_EOL, Console::FG_GREEN);
// TODO generate api references.txt
}
protected function findFiles($path, $except = ['README.md'])
{
$path = FileHelper::normalizePath($path);
$options = [
'only' => ['*.md'],
'except' => $except,
];
return FileHelper::findFiles($path, $options);
}
/**
* @return GuideRenderer
*/
protected function findRenderer($template)
{
$rendererClass = 'yii\\apidoc\\templates\\' . $template . '\\GuideRenderer';
if (!class_exists($rendererClass)) {
$this->stderr('Renderer not found.' . PHP_EOL);
return false;
}
return new $rendererClass();
}
}
\ No newline at end of file
......@@ -11,7 +11,7 @@ use cebe\markdown\GithubMarkdown;
use phpDocumentor\Reflection\DocBlock\Type\Collection;
use yii\apidoc\models\MethodDoc;
use yii\apidoc\models\TypeDoc;
use yii\apidoc\templates\BaseRenderer;
use yii\apidoc\renderers\BaseRenderer;
use yii\helpers\Inflector;
use yii\helpers\Markdown;
......@@ -35,7 +35,7 @@ class ApiMarkdown extends GithubMarkdown
parent::prepare();
// add references to guide pages
$this->references = array_merge($this->references, static::$renderer->getGuideReferences());
$this->references = array_merge($this->references, static::$renderer->guideReferences);
}
/**
......@@ -140,9 +140,9 @@ class ApiMarkdown extends GithubMarkdown
// Collection resolves relative types
$typeName = (new Collection([$typeName], $context->phpDocContext))->__toString();
}
$type = static::$renderer->context->getType($typeName);
$type = static::$renderer->apiContext->getType($typeName);
if ($type === null) {
static::$renderer->context->errors[] = [
static::$renderer->apiContext->errors[] = [
'file' => ($context !== null) ? $context->sourceFile : null,
'message' => 'broken link to ' . $typeName . '::' . $subjectName . (($context !== null) ? ' in ' . $context->name : ''),
];
......@@ -159,11 +159,11 @@ class ApiMarkdown extends GithubMarkdown
}
}
return [
static::$renderer->subjectLink($subject, $title),
static::$renderer->createSubjectLink($subject, $title),
$offset
];
} else {
static::$renderer->context->errors[] = [
static::$renderer->apiContext->errors[] = [
'file' => ($context !== null) ? $context->sourceFile : null,
'message' => 'broken link to ' . $type->name . '::' . $subjectName . (($context !== null) ? ' in ' . $context->name : ''),
];
......@@ -175,7 +175,7 @@ class ApiMarkdown extends GithubMarkdown
}
} elseif ($context !== null && ($subject = $context->findSubject($object)) !== null) {
return [
static::$renderer->subjectLink($subject, $title),
static::$renderer->createSubjectLink($subject, $title),
$offset
];
}
......@@ -183,13 +183,13 @@ class ApiMarkdown extends GithubMarkdown
// Collection resolves relative types
$object = (new Collection([$object], $context->phpDocContext))->__toString();
}
if (($type = static::$renderer->context->getType($object)) !== null) {
if (($type = static::$renderer->apiContext->getType($object)) !== null) {
return [
static::$renderer->typeLink($type, $title),
static::$renderer->createTypeLink($type, null, $title),
$offset
];
}
static::$renderer->context->errors[] = [
static::$renderer->apiContext->errors[] = [
'file' => ($context !== null) ? $context->sourceFile : null,
'message' => 'broken link to ' . $object . (($context !== null) ? ' in ' . $context->name : ''),
];
......@@ -228,7 +228,7 @@ class ApiMarkdown extends GithubMarkdown
}
if (is_string($context)) {
$context = static::$renderer->context->getType($context);
$context = static::$renderer->apiContext->getType($context);
}
Markdown::$flavors['api']->context = $context;
......
......@@ -5,7 +5,7 @@
* @license http://www.yiiframework.com/license/
*/
namespace yii\apidoc\templates;
namespace yii\apidoc\renderers;
use Yii;
use yii\apidoc\models\ClassDoc;
......@@ -25,48 +25,13 @@ use yii\console\Controller;
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
abstract class BaseRenderer extends Component
abstract class ApiRenderer extends BaseRenderer
{
/**
* @var Context the [[Context]] currently being rendered.
*/
public $context;
/**
* @var array files for guide pages
*/
public $markDownFiles = [];
/**
* Renders a given [[Context]].
*
* @param Context $context the api documentation context to render.
* @param Controller $controller the apidoc controller instance. Can be used to control output.
*/
public abstract function renderApi($context, $controller);
/**
* Renders a given [[Context]].
*
* @param array $files list of markdown files to render
* @param Context $context the api documentation context to render.
* @param Controller $controller the apidoc controller instance. Can be used to control output.
* @return
*/
public abstract function renderMarkdownFiles($controller);
/**
* creates a link to a type (class, interface or trait)
* @param ClassDoc|InterfaceDoc|TraitDoc $types
* @param string $title
* @return string
*/
public abstract function typeLink($types, $title = null);
/**
* creates a link to a subject
* @param PropertyDoc|MethodDoc|ConstDoc|EventDoc $subject
* @param string $title
* @return string
* @param $targetDir
*/
public abstract function subjectLink($subject, $title = null);
public abstract function render($context, $targetDir);
}
\ No newline at end of file
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\apidoc\renderers;
use Yii;
use yii\apidoc\helpers\ApiMarkdown;
use yii\apidoc\models\BaseDoc;
use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\ConstDoc;
use yii\apidoc\models\Context;
use yii\apidoc\models\EventDoc;
use yii\apidoc\models\InterfaceDoc;
use yii\apidoc\models\MethodDoc;
use yii\apidoc\models\PropertyDoc;
use yii\apidoc\models\TraitDoc;
use yii\apidoc\models\TypeDoc;
use yii\base\Component;
use yii\console\Controller;
use yii\helpers\Html;
/**
* Base class for all documentation renderers
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
abstract class BaseRenderer extends Component
{
public $apiUrl;
/**
* @var Context the [[Context]] currently being rendered.
*/
public $apiContext;
/**
* @var Controller the apidoc controller instance. Can be used to control output.
*/
public $controller;
public $guideUrl;
public $guideReferences = [];
public function init()
{
ApiMarkdown::$renderer = $this;
}
/**
* creates a link to a type (class, interface or trait)
* @param ClassDoc|InterfaceDoc|TraitDoc|ClassDoc[]|InterfaceDoc[]|TraitDoc[] $types
* @param string $title a title to be used for the link TODO check whether [[yii\...|Class]] is supported
* @param BaseDoc $context
* @return string
*/
public function createTypeLink($types, $context = null, $title = null)
{
if (!is_array($types)) {
$types = [$types];
}
if (count($types) > 1) {
$title = null;
}
$links = [];
foreach($types as $type) {
$postfix = '';
if (!is_object($type)) {
if (substr($type, -2, 2) == '[]') {
$postfix = '[]';
$type = substr($type, 0, -2);
}
if (($t = $this->apiContext->getType(ltrim($type, '\\'))) !== null) {
$type = $t;
} elseif ($type[0] !== '\\' && ($t = $this->apiContext->getType($this->resolveNamespace($context) . '\\' . ltrim($type, '\\'))) !== null) {
$type = $t;
} else {
ltrim($type, '\\');
}
}
if (!is_object($type)) {
$links[] = $type;
} else {
$linkText = $type->name;
if ($title !== null) {
$linkText = $title;
}
$links[] = $this->generateLink($linkText, $this->generateApiUrl($type->name)) . $postfix;
}
}
return implode('|', $links);
}
/**
* creates a link to a subject
* @param PropertyDoc|MethodDoc|ConstDoc|EventDoc $subject
* @param string $title
* @return string
*/
public function createSubjectLink($subject, $title = null)
{
if ($title === null) {
if ($subject instanceof MethodDoc) {
$title = $subject->name . '()';
} else {
$title = $subject->name;
}
}
if (($type = $this->apiContext->getType($subject->definedBy)) === null) {
return $subject->name;
} else {
$link = $this->generateApiUrl($type->name);
if ($subject instanceof MethodDoc) {
$link .= '#' . $subject->name . '()';
} else {
$link .= '#' . $subject->name;
}
$link .= '-detail';
return Html::a($title, null, ['href' => $link]);
}
}
/**
* @param BaseDoc $context
*/
private function resolveNamespace($context)
{
// TODO use phpdoc Context for this
if ($context === null) {
return '';
}
if ($context instanceof TypeDoc) {
return $context->namespace;
}
if ($context->hasProperty('definedBy')) {
$type = $this->apiContext->getType($context);
if ($type !== null) {
return $type->namespace;
}
}
return '';
}
/**
* generate link markup
* @param $text
* @param $href
* @return mixed
*/
protected abstract function generateLink($text, $href);
/**
* Generate an url to a type in apidocs
* @param $typeName
* @return mixed
*/
public abstract function generateApiUrl($typeName);
}
\ No newline at end of file
......@@ -5,18 +5,34 @@
* @license http://www.yiiframework.com/license/
*/
namespace yii\apidoc\templates\offline;
namespace yii\apidoc\renderers;
use Yii;
use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\ConstDoc;
use yii\apidoc\models\Context;
use yii\apidoc\models\EventDoc;
use yii\apidoc\models\InterfaceDoc;
use yii\apidoc\models\MethodDoc;
use yii\apidoc\models\PropertyDoc;
use yii\apidoc\models\TraitDoc;
use yii\base\Component;
use yii\console\Controller;
/**
* Base class for all Guide documentation renderers
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class Renderer extends \yii\apidoc\templates\html\Renderer
abstract class GuideRenderer extends BaseRenderer
{
public $apiLayout = '@yii/apidoc/templates/offline/views/offline.php';
public $indexView = '@yii/apidoc/templates/offline/views/index.php';
/**
* Render markdown files
*
* @param array $files list of markdown files to render
* @param $targetDir
*/
public abstract function render($files, $targetDir);
public $pageTitle = 'Yii Framework 2.0 API Documentation';
}
\ No newline at end of file
......@@ -7,26 +7,29 @@
namespace yii\apidoc\templates\bootstrap;
use yii\apidoc\helpers\ApiMarkdown;
use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\ConstDoc;
use yii\apidoc\models\Context;
use yii\apidoc\models\EventDoc;
use yii\apidoc\models\InterfaceDoc;
use yii\apidoc\models\MethodDoc;
use yii\apidoc\models\PropertyDoc;
use yii\apidoc\models\TraitDoc;
use yii\console\Controller;
use Yii;
use yii\helpers\Console;
use yii\helpers\Html;
/**
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class Renderer extends \yii\apidoc\templates\html\Renderer
class ApiRenderer extends \yii\apidoc\templates\html\ApiRenderer
{
public $apiLayout = '@yii/apidoc/templates/bootstrap/layouts/api.php';
public $guideLayout = '@yii/apidoc/templates/bootstrap/layouts/guide.php';
public $layout = '@yii/apidoc/templates/bootstrap/layouts/api.php';
public $indexView = '@yii/apidoc/templates/bootstrap/views/index.php';
public $pageTitle = 'Yii Framework 2.0 Documentation';
public $guideUrl;
public $extensions = [
'apidoc',
'authclient',
......@@ -48,35 +51,60 @@ class Renderer extends \yii\apidoc\templates\html\Renderer
];
/**
* Renders a given [[Context]].
*
* @param Context $context the api documentation context to render.
* @param Controller $controller the apidoc controller instance. Can be used to control output.
* @inheritdoc
*/
public function renderApi($context, $controller)
public function render($context, $targetDir)
{
parent::renderApi($context, $controller);
$dir = Yii::getAlias($this->targetDir);
$types = array_merge($context->classes, $context->interfaces, $context->traits);
$controller->stdout('generating extension index files...');
foreach($this->extensions as $ext) {
$extTypes = [];
foreach($this->extensions as $k => $ext) {
$extType = $this->filterTypes($types, $ext);
if (empty($extType)) {
unset($this->extensions[$k]);
continue;
}
$extTypes[$ext] = $extType;
}
// render view files
parent::render($context, $targetDir);
if ($this->controller !== null) {
$this->controller->stdout('generating extension index files...');
}
foreach($extTypes as $ext => $extType) {
$readme = @file_get_contents("https://raw.github.com/yiisoft/yii2-$ext/master/README.md");
$indexFileContent = $this->renderWithLayout($this->indexView, [
'docContext' => $context,
'types' => $this->filterTypes($types, $ext),
'types' => $extType,
'readme' => $readme ?: null,
]);
file_put_contents($dir . "/ext_{$ext}_index.html", $indexFileContent);
file_put_contents($targetDir . "/ext-{$ext}-index.html", $indexFileContent);
}
$yiiTypes = $this->filterTypes($types, 'yii');
if (empty($yiiTypes)) {
// $readme = @file_get_contents("https://raw.github.com/yiisoft/yii2-framework/master/README.md");
$indexFileContent = $this->renderWithLayout($this->indexView, [
'docContext' => $context,
'types' => $this->filterTypes($types, 'app'),
'readme' => null,
]);
} else {
$readme = @file_get_contents("https://raw.github.com/yiisoft/yii2-framework/master/README.md");
$indexFileContent = $this->renderWithLayout($this->indexView, [
'docContext' => $context,
'types' => $this->filterTypes($types, 'yii'),
'types' => $yiiTypes,
'readme' => $readme ?: null,
]);
file_put_contents($dir . '/index.html', $indexFileContent);
$controller->stdout('done.' . PHP_EOL, Console::FG_GREEN);
}
file_put_contents($targetDir . '/index.html', $indexFileContent);
if ($this->controller !== null) {
$this->controller->stdout('done.' . PHP_EOL, Console::FG_GREEN);
}
}
public function getNavTypes($type, $types)
......@@ -130,77 +158,4 @@ class Renderer extends \yii\apidoc\templates\html\Renderer
}
return $types;
}
/**
* Renders a given [[Context]].
*
* @param Controller $controller the apidoc controller instance. Can be used to control output.
*/
public function renderMarkdownFiles($controller)
{
$files = $this->markDownFiles;
$dir = Yii::getAlias($this->targetDir);
if (!is_dir($dir)) {
mkdir($dir, 0777, true);
}
ApiMarkdown::$renderer = $this;
$fileCount = count($files) + 1;
Console::startProgress(0, $fileCount, 'Rendering markdown files: ', false);
$done = 0;
$fileData = [];
$headlines = [];
foreach($files as $file) {
$fileData[$file] = file_get_contents($file);
if (basename($file) == 'index.md') {
continue; // to not add index file to nav
}
if (preg_match("/^(.*)\n=+/", $fileData[$file], $matches)) {
$headlines[$file] = $matches[1];
} else {
$headlines[$file] = basename($file);
}
}
foreach($fileData as $file => $content) {
$output = ApiMarkdown::process($content); // TODO generate links to yiiframework.com by default
$output = $this->fixMarkdownLinks($output);
if ($this->guideLayout !== false) {
$params = [
'headlines' => $headlines,
'currentFile' => $file,
'content' => $output,
];
$output = $this->getView()->renderFile($this->guideLayout, $params, $this);
}
$fileName = $this->generateGuideFileName($file);
file_put_contents($dir . '/' . $fileName, $output);
Console::updateProgress(++$done, $fileCount);
}
Console::updateProgress(++$done, $fileCount);
Console::endProgress(true);
$controller->stdout('done.' . PHP_EOL, Console::FG_GREEN);
}
protected function generateGuideFileName($file)
{
return 'guide_' . basename($file, '.md') . '.html';
}
public function getGuideReferences()
{
$refs = [];
foreach($this->markDownFiles as $file) {
$refName = 'guide-' . basename($file, '.md');
$refs[$refName] = ['url' => $this->generateGuideFileName($file)];
}
return $refs;
}
protected function fixMarkdownLinks($content)
{
$content = preg_replace('/href\s*=\s*"([^"\/]+)\.md(#.*)?"/i', 'href="guide_\1.html\2"', $content);
return $content;
}
}
\ No newline at end of file
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\apidoc\templates\bootstrap;
use yii\apidoc\helpers\ApiMarkdown;
use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\ConstDoc;
use yii\apidoc\models\Context;
use yii\apidoc\models\EventDoc;
use yii\apidoc\models\InterfaceDoc;
use yii\apidoc\models\MethodDoc;
use yii\apidoc\models\PropertyDoc;
use yii\apidoc\models\TraitDoc;
use yii\console\Controller;
use Yii;
use yii\helpers\Console;
use yii\helpers\Html;
/**
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class GuideRenderer extends \yii\apidoc\templates\html\GuideRenderer
{
public $layout = '@yii/apidoc/templates/bootstrap/layouts/guide.php';
public $extensions = [
'apidoc',
'authclient',
'bootstrap',
'codeception',
'composer',
'debug',
'elasticsearch',
'faker',
'gii',
'imagine',
'jui',
'mongodb',
'redis',
'smarty',
'sphinx',
'swiftmailer',
'twig',
];
//
// /**
// * Renders a given [[Context]].
// *
// * @param Controller $controller the apidoc controller instance. Can be used to control output.
// */
// public function renderMarkdownFiles($controller)
// {
// $files = $this->markDownFiles;
// $dir = Yii::getAlias($this->targetDir);
// if (!is_dir($dir)) {
// mkdir($dir, 0777, true);
// }
//
// ApiMarkdown::$renderer = $this;
//
// $fileCount = count($files) + 1;
// Console::startProgress(0, $fileCount, 'Rendering markdown files: ', false);
// $done = 0;
// $fileData = [];
// $headlines = [];
// foreach($files as $file) {
// $fileData[$file] = file_get_contents($file);
// if (basename($file) == 'index.md') {
// continue; // to not add index file to nav
// }
// if (preg_match("/^(.*)\n=+/", $fileData[$file], $matches)) {
// $headlines[$file] = $matches[1];
// } else {
// $headlines[$file] = basename($file);
// }
// }
//
// foreach($fileData as $file => $content) {
// $output = ApiMarkdown::process($content); // TODO generate links to yiiframework.com by default
// $output = $this->fixMarkdownLinks($output);
// if ($this->guideLayout !== false) {
// $params = [
// 'headlines' => $headlines,
// 'currentFile' => $file,
// 'content' => $output,
// ];
// $output = $this->getView()->renderFile($this->guideLayout, $params, $this);
// }
// $fileName = $this->generateGuideFileName($file);
// file_put_contents($dir . '/' . $fileName, $output);
// Console::updateProgress(++$done, $fileCount);
// }
// Console::updateProgress(++$done, $fileCount);
// Console::endProgress(true);
// $controller->stdout('done.' . PHP_EOL, Console::FG_GREEN);
// }
//
}
\ No newline at end of file
<?php
use yii\apidoc\templates\bootstrap\ApiRenderer;
use yii\apidoc\templates\bootstrap\SideNavWidget;
use yii\helpers\StringHelper;
/**
* @var yii\web\View $this
* @var string $content
*/
/** @var ApiRenderer $renderer */
$renderer = $this->context;
$this->beginContent('@yii/apidoc/templates/bootstrap/layouts/main.php'); ?>
<div class="row">
<div class="col-md-2">
<?php
$types = $this->context->getNavTypes(isset($type) ? $type : null, $types);
$types = $renderer->getNavTypes(isset($type) ? $type : null, $types);
ksort($types);
$nav = [];
foreach($types as $i=>$class) {
......@@ -28,7 +33,7 @@ $this->beginContent('@yii/apidoc/templates/bootstrap/layouts/main.php'); ?>
}
$nav[$namespace]['items'][] = [
'label' => StringHelper::basename($class->name),
'url' => './' . $this->context->generateUrl($class->name),
'url' => './' . $renderer->generateApiUrl($class->name),
'active' => isset($type) && ($class->name == $type->name),
];
} ?>
......
......@@ -3,6 +3,7 @@ use yii\apidoc\templates\bootstrap\SideNavWidget;
/**
* @var yii\web\View $this
* @var string $content
*/
$this->beginContent('@yii/apidoc/templates/bootstrap/layouts/main.php'); ?>
......
......@@ -45,6 +45,11 @@ $this->beginPage();
'renderInnerContainer' => false,
'view' => $this,
]);
$nav = [
['label' => 'Class reference', 'url' => './index.html'],
];
if (!empty($this->context->extensions))
{
$extItems = [];
foreach($this->context->extensions as $ext) {
$extItems[] = [
......@@ -52,11 +57,9 @@ $this->beginPage();
'url' => "./ext_{$ext}_index.html",
];
}
$nav = [
['label' => 'Class reference', 'url' => './index.html'],
// ['label' => 'Application API', 'url' => '/site/about'],
['label' => 'Extensions', 'items' => $extItems],
];
$nav[] = ['label' => 'Extensions', 'items' => $extItems];
}
if ($this->context->guideUrl !== null) {
$nav[] = ['label' => 'Guide', 'url' => $this->context->guideUrl . 'guide_index.html'];
}
......
......@@ -6,8 +6,11 @@ use yii\apidoc\models\TraitDoc;
/**
* @var ClassDoc[]|InterfaceDoc[]|TraitDoc[] $types
* @var yii\web\View $this
* @var \yii\apidoc\templates\html\ApiRenderer $renderer
*/
$renderer = $this->context;
if (isset($readme)) {
echo \yii\apidoc\helpers\ApiMarkdown::process($readme);
}
......@@ -29,7 +32,7 @@ ksort($types);
foreach($types as $i=>$class):
?>
<tr>
<td><?= $this->context->typeLink($class, $class->name) ?></td>
<td><?= $renderer->createTypeLink($class, $class, $class->name) ?></td>
<td><?= \yii\apidoc\helpers\ApiMarkdown::process($class->shortDescription, $class, true) ?></td>
</tr>
<?php endforeach; ?>
......
......@@ -7,25 +7,17 @@
namespace yii\apidoc\templates\html;
use yii\apidoc\helpers\ApiMarkdown;
use yii\apidoc\models\BaseDoc;
use yii\apidoc\models\ConstDoc;
use yii\apidoc\models\EventDoc;
use yii\apidoc\models\MethodDoc;
use yii\apidoc\models\PropertyDoc;
use yii\apidoc\models\TypeDoc;
use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\Context;
use yii\apidoc\models\InterfaceDoc;
use yii\apidoc\models\TraitDoc;
use yii\apidoc\templates\BaseRenderer;
use yii\apidoc\renderers\ApiRenderer as BaseApiRenderer;
use yii\base\ViewContextInterface;
use yii\console\Controller;
use yii\helpers\Console;
use yii\helpers\Html;
use Yii;
use yii\web\AssetManager;
use yii\web\View;
use Yii;
/**
* The base class for HTML API documentation renderers.
......@@ -35,20 +27,16 @@ use yii\web\View;
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
abstract class Renderer extends BaseRenderer implements ViewContextInterface
class ApiRenderer extends BaseApiRenderer implements ViewContextInterface
{
/**
* @var string directory to use for output of html files. Can be a path alias.
*/
public $targetDir;
/**
* @var string string to use as the title of the generated page.
*/
public $pageTitle = 'Yii Framework 2.0 API Documentation';
public $pageTitle;
/**
* @var string path or alias of the layout file to use.
*/
public $apiLayout;
public $layout;
/**
* @var string path or alias of the view file to use for rendering types (classes, interfaces, traits).
*/
......@@ -61,11 +49,16 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
* @var View
*/
private $_view;
private $_targetDir;
public function init()
{
ApiMarkdown::$renderer = $this;
parent::init();
if ($this->pageTitle === null) {
$this->pageTitle = 'Yii Framework 2.0 API Documentation'; // TODO guess page title
}
}
/**
......@@ -75,7 +68,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
{
if ($this->_view === null) {
$this->_view = new View();
$assetPath = Yii::getAlias($this->targetDir) . '/assets';
$assetPath = Yii::getAlias($this->_targetDir) . '/assets';
if (!is_dir($assetPath)) {
mkdir($assetPath);
}
......@@ -91,153 +84,69 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
* Renders a given [[Context]].
*
* @param Context $context the api documentation context to render.
* @param Controller $controller the apidoc controller instance. Can be used to control output.
* @param $targetDir
*/
public function renderApi($context, $controller)
public function render($context, $targetDir)
{
$this->context = $context;
$dir = Yii::getAlias($this->targetDir);
if (!is_dir($dir)) {
mkdir($dir, 0777, true);
}
$this->apiContext = $context;
$this->_targetDir = $targetDir;
$types = array_merge($context->classes, $context->interfaces, $context->traits);
$typeCount = count($types) + 1;
if ($this->controller !== null) {
Console::startProgress(0, $typeCount, 'Rendering files: ', false);
}
$done = 0;
foreach($types as $type) {
$fileContent = $this->renderWithLayout($this->typeView, [
'type' => $type,
'docContext' => $context,
'apiContext' => $context,
'types' => $types,
]);
file_put_contents($dir . '/' . $this->generateFileName($type->name), $fileContent);
file_put_contents($targetDir . '/' . $this->generateFileName($type->name), $fileContent);
if ($this->controller !== null) {
Console::updateProgress(++$done, $typeCount);
}
}
$indexFileContent = $this->renderWithLayout($this->indexView, [
'docContext' => $context,
'apiContext' => $context,
'types' => $types,
]);
file_put_contents($dir . '/index.html', $indexFileContent);
file_put_contents($targetDir . '/index.html', $indexFileContent);
if ($this->controller !== null) {
Console::updateProgress(++$done, $typeCount);
Console::endProgress(true);
$controller->stdout('done.' . PHP_EOL, Console::FG_GREEN);
$this->controller->stdout('done.' . PHP_EOL, Console::FG_GREEN);
}
}
protected function renderWithLayout($viewFile, $params)
{
$output = $this->getView()->render($viewFile, $params, $this);
if ($this->apiLayout !== false) {
if ($this->layout !== false) {
$params['content'] = $output;
return $this->getView()->renderFile($this->apiLayout, $params, $this);
return $this->getView()->renderFile($this->layout, $params, $this);
} else {
return $output;
}
}
/**
* creates a link to a type (class, interface or trait)
* @param ClassDoc|InterfaceDoc|TraitDoc $types
* @param BaseDoc $context
* @return string
*/
public function typeLink($types, $context = null)
{
if (!is_array($types)) {
$types = [$types];
}
$links = [];
foreach($types as $type) {
$postfix = '';
if (!is_object($type)) {
if (substr($type, -2, 2) == '[]') {
$postfix = '[]';
$type = substr($type, 0, -2);
}
if (($t = $this->context->getType(ltrim($type, '\\'))) !== null) {
$type = $t;
} elseif ($type[0] !== '\\' && ($t = $this->context->getType($this->resolveNamespace($context) . '\\' . ltrim($type, '\\'))) !== null) {
$type = $t;
} else {
ltrim($type, '\\');
}
}
if (!is_object($type)) {
$links[] = $type;
} else {
$links[] = Html::a(
$type->name,
null,
['href' => $this->generateUrl($type->name)]
) . $postfix;
}
}
return implode('|', $links);
}
/**
* creates a link to a subject
* @param PropertyDoc|MethodDoc|ConstDoc|EventDoc $subject
* @param string $title
* @return string
*/
public function subjectLink($subject, $title = null)
{
if ($title === null) {
if ($subject instanceof MethodDoc) {
$title = $subject->name . '()';
} else {
$title = $subject->name;
}
}
if (($type = $this->context->getType($subject->definedBy)) === null) {
return $subject->name;
} else {
$link = $this->generateUrl($type->name);
if ($subject instanceof MethodDoc) {
$link .= '#' . $subject->name . '()';
} else {
$link .= '#' . $subject->name;
}
$link .= '-detail';
return Html::a($title, null, ['href' => $link]);
}
}
/**
* @param BaseDoc $context
*/
private function resolveNamespace($context)
{
// TODO use phpdoc Context for this
if ($context === null) {
return '';
}
if ($context instanceof TypeDoc) {
return $context->namespace;
}
if ($context->hasProperty('definedBy')) {
$type = $this->context->getType($context);
if ($type !== null) {
return $type->namespace;
}
}
return '';
}
/**
* @param ClassDoc $class
* @return string
*/
public function renderInheritance($class)
{
$parents = [];
$parents[] = $this->typeLink($class);
$parents[] = $this->createTypeLink($class);
while ($class->parentClass !== null) {
if(isset($this->context->classes[$class->parentClass])) {
$class = $this->context->classes[$class->parentClass];
$parents[] = $this->typeLink($class);
if(isset($this->apiContext->classes[$class->parentClass])) {
$class = $this->apiContext->classes[$class->parentClass];
$parents[] = $this->createTypeLink($class);
} else {
$parents[] = $class->parentClass; // TODO link to php.net
break;
......@@ -255,8 +164,8 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
$interfaces = [];
sort($names, SORT_STRING);
foreach($names as $interface) {
if(isset($this->context->interfaces[$interface])) {
$interfaces[] = $this->typeLink($this->context->interfaces[$interface]);
if(isset($this->apiContext->interfaces[$interface])) {
$interfaces[] = $this->createTypeLink($this->apiContext->interfaces[$interface]);
} else {
$interfaces[] = $interface; // TODO link to php.net
}
......@@ -273,8 +182,8 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
$traits = [];
sort($names, SORT_STRING);
foreach($names as $trait) {
if(isset($this->context->traits[$trait])) {
$traits[] = $this->typeLink($this->context->traits[$trait]);
if(isset($this->apiContext->traits[$trait])) {
$traits[] = $this->createTypeLink($this->apiContext->traits[$trait]);
} else {
$traits[] = $trait; // TODO link to php.net
}
......@@ -291,8 +200,8 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
$classes = [];
sort($names, SORT_STRING);
foreach($names as $class) {
if(isset($this->context->classes[$class])) {
$classes[] = $this->typeLink($this->context->classes[$class]);
if(isset($this->apiContext->classes[$class])) {
$classes[] = $this->createTypeLink($this->apiContext->classes[$class]);
} else {
$classes[] = $class; // TODO link to php.net
}
......@@ -316,7 +225,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
}
return implode('<br />', $sig);
}
return $this->typeLink($property->types) . ' ' . $property->name . ' = ' . ($property->defaultValue === null ? 'null' : $property->defaultValue);
return $this->createTypeLink($property->types) . ' ' . $property->name . ' = ' . ($property->defaultValue === null ? 'null' : $property->defaultValue);
}
/**
......@@ -334,20 +243,20 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
}
return ($method->isReturnByReference ? '<b>&</b>' : '')
. ($method->returnType === null ? 'void' : $this->typeLink($method->returnTypes))
. ' ' . $this->subjectLink($method, $method->name) . '( '
. ($method->returnType === null ? 'void' : $this->createTypeLink($method->returnTypes))
. ' ' . $this->createSubjectLink($method, $method->name) . '( '
. implode(', ', $params)
. ' )';
}
public function generateUrl($typeName)
public function generateApiUrl($typeName)
{
return $this->generateFileName($typeName);
}
protected function generateFileName($typeName)
{
return strtolower(str_replace('\\', '_', $typeName)) . '.html';
return strtolower(str_replace('\\', '-', $typeName)) . '.html';
}
/**
......@@ -359,4 +268,15 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
{
return Yii::getAlias('@yii/apidoc/templates/html/views/' . $view);
}
/**
* generate link markup
* @param $text
* @param $href
* @return mixed
*/
protected function generateLink($text, $href)
{
return Html::a($text, null, ['href' => $href]);
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\apidoc\templates\html;
use yii\apidoc\helpers\ApiMarkdown;
use yii\console\Controller;
use yii\helpers\Console;
use yii\apidoc\renderers\GuideRenderer as BaseGuideRenderer;
use Yii;
use yii\helpers\Html;
use yii\web\AssetManager;
use yii\web\View;
/**
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
abstract class GuideRenderer extends BaseGuideRenderer
{
public $pageTitle;
public $layout;
/**
* @var View
*/
private $_view;
private $_targetDir;
public function init()
{
parent::init();
if ($this->pageTitle === null) {
$this->pageTitle = 'Yii Framework 2.0 API Documentation'; // TODO guess page title
}
}
/**
* @return View the view instance
*/
public function getView()
{
if ($this->_view === null) {
$this->_view = new View();
$assetPath = Yii::getAlias($this->_targetDir) . '/assets';
if (!is_dir($assetPath)) {
mkdir($assetPath);
}
$this->_view->assetManager = new AssetManager([
'basePath' => $assetPath,
'baseUrl' => './assets',
]);
}
return $this->_view;
}
/**
* Renders a given [[Context]].
*
* @param Controller $controller the apidoc controller instance. Can be used to control output.
*/
public function render($files, $targetDir)
{
$this->_targetDir = $targetDir;
$fileCount = count($files) + 1;
if ($this->controller !== null) {
Console::startProgress(0, $fileCount, 'Rendering markdown files: ', false);
}
$done = 0;
$fileData = [];
$headlines = [];
foreach($files as $file) {
$fileData[$file] = file_get_contents($file);
if (basename($file) == 'index.md') {
continue; // to not add index file to nav
}
if (preg_match("/^(.*)\n=+/", $fileData[$file], $matches)) {
$headlines[$file] = $matches[1];
} else {
$headlines[$file] = basename($file);
}
}
foreach($fileData as $file => $content) {
$output = ApiMarkdown::process($content); // TODO generate links to yiiframework.com by default
$output = $this->fixMarkdownLinks($output);
if ($this->layout !== false) {
$params = [
'headlines' => $headlines,
'currentFile' => $file,
'content' => $output,
];
$output = $this->getView()->renderFile($this->layout, $params, $this);
}
$fileName = $this->generateGuideFileName($file);
file_put_contents($targetDir . '/' . $fileName, $output);
if ($this->controller !== null) {
Console::updateProgress(++$done, $fileCount);
}
}
if ($this->controller !== null) {
Console::updateProgress(++$done, $fileCount);
Console::endProgress(true);
$this->controller->stdout('done.' . PHP_EOL, Console::FG_GREEN);
}
}
// TODO move these to guide renderer
protected function generateGuideFileName($file)
{
return 'guide_' . basename($file, '.md') . '.html';
}
public function getGuideReferences()
{
// TODO implement for api docs
// $refs = [];
// foreach($this->markDownFiles as $file) {
// $refName = 'guide-' . basename($file, '.md');
// $refs[$refName] = ['url' => $this->generateGuideFileName($file)];
// }
// return $refs;
}
protected function fixMarkdownLinks($content)
{
$content = preg_replace('/href\s*=\s*"([^"\/]+)\.md(#.*)?"/i', 'href="guide_\1.html\2"', $content);
return $content;
}
/**
* generate link markup
* @param $text
* @param $href
* @return mixed
*/
protected function generateLink($text, $href)
{
return Html::a($text, null, ['href' => $href]);
}
/**
* Generate an url to a type in apidocs
* @param $typeName
* @return mixed
*/
public function generateApiUrl($typeName)
{
// TODO: Implement generateApiUrl() method.
return $this->apiUrl . '...';
}
}
\ No newline at end of file
The html API doc template
-------------------------
=========================
This templates provides view files and a Renderer class that can be reused in other html templates.
\ No newline at end of file
......@@ -7,8 +7,11 @@ use yii\helpers\ArrayHelper;
/**
* @var ClassDoc $type
* @var yii\web\View $this
* @var \yii\apidoc\templates\html\ApiRenderer $renderer
*/
$renderer = $this->context;
if (empty($type->constants)) {
return;
}
......@@ -34,7 +37,7 @@ ArrayHelper::multisort($constants, 'name');
<td><?= $constant->name ?><a name="<?= $constant->name ?>-detail"></a></td>
<td><?= $constant->value ?></td>
<td><?= APiMarkdown::process($constant->shortDescription . "\n" . $constant->description, $constant->definedBy, true) ?></td>
<td><?= $this->context->typeLink($constant->definedBy) ?></td>
<td><?= $renderer->createTypeLink($constant->definedBy) ?></td>
</tr>
<?php endforeach; ?>
</table>
......
......@@ -7,8 +7,11 @@ use yii\helpers\ArrayHelper;
/**
* @var ClassDoc $type
* @var yii\web\View $this
* @var \yii\apidoc\templates\html\ApiRenderer $renderer
*/
$renderer = $this->context;
if (empty($type->events)) {
return;
}
......@@ -31,15 +34,15 @@ ArrayHelper::multisort($events, 'name');
</tr>
<?php foreach($events as $event): ?>
<tr<?= $event->definedBy != $type->name ? ' class="inherited"' : '' ?> id="<?= $event->name ?>">
<td><?= $this->context->subjectLink($event) ?></td>
<td><?= $this->context->typeLink($event->types) ?></td>
<td><?= $renderer->createSubjectLink($event) ?></td>
<td><?= $renderer->createTypeLink($event->types) ?></td>
<td>
<?= ApiMarkdown::process($event->shortDescription, $event->definedBy, true) ?>
<?php if(!empty($event->since)): ?>
(available since version <?php echo $event->since; ?>)
<?php endif; ?>
</td>
<td><?= $this->context->typeLink($event->definedBy) ?></td>
<td><?= $renderer->createTypeLink($event->definedBy) ?></td>
</tr>
<?php endforeach; ?>
</table>
......
......@@ -8,8 +8,11 @@ use yii\helpers\ArrayHelper;
/**
* @var ClassDoc|TraitDoc $type
* @var yii\web\View $this
* @var \yii\apidoc\templates\html\ApiRenderer $renderer
*/
$renderer = $this->context;
$methods = $type->getNativeMethods();
if (empty($methods)) {
return;
......@@ -33,27 +36,27 @@ ArrayHelper::multisort($methods, 'name');
<table class="summaryTable table table-striped table-bordered table-hover">
<tr><td colspan="3">
<div class="signature2"><?= $this->context->renderMethodSignature($method) ?></div>
<div class="signature2"><?= $renderer->renderMethodSignature($method) ?></div>
</td></tr>
<?php if(!empty($method->params) || !empty($method->return) || !empty($method->exceptions)): ?>
<?php foreach($method->params as $param): ?>
<tr>
<td class="paramNameCol"><?= $param->name ?></td>
<td class="paramTypeCol"><?= $this->context->typeLink($param->types) ?></td>
<td class="paramTypeCol"><?= $renderer->createTypeLink($param->types) ?></td>
<td class="paramDescCol"><?= ApiMarkdown::process($param->description, $type) ?></td>
</tr>
<?php endforeach; ?>
<?php if(!empty($method->return)): ?>
<tr>
<td class="paramNameCol"><?= 'return'; ?></td>
<td class="paramTypeCol"><?= $this->context->typeLink($method->returnTypes); ?></td>
<td class="paramTypeCol"><?= $renderer->createTypeLink($method->returnTypes); ?></td>
<td class="paramDescCol"><?= ApiMarkdown::process($method->return, $type); ?></td>
</tr>
<?php endif; ?>
<?php foreach($method->exceptions as $exception => $description): ?>
<tr>
<td class="paramNameCol"><?= 'throws' ?></td>
<td class="paramTypeCol"><?= $this->context->typeLink($exception) ?></td>
<td class="paramTypeCol"><?= $renderer->createTypeLink($exception) ?></td>
<td class="paramDescCol"><?= ApiMarkdown::process($description, $type) ?></td>
</tr>
<?php endforeach; ?>
......
......@@ -10,8 +10,11 @@ use yii\helpers\ArrayHelper;
* @var ClassDoc|InterfaceDoc|TraitDoc $type
* @var boolean $protected
* @var yii\web\View $this
* @var \yii\apidoc\templates\html\ApiRenderer $renderer
*/
$renderer = $this->context;
if ($protected && count($type->getProtectedMethods()) == 0 || !$protected && count($type->getPublicMethods()) == 0) {
return;
} ?>
......@@ -36,9 +39,9 @@ ArrayHelper::multisort($methods, 'name');
foreach($methods as $method): ?>
<?php if($protected && $method->visibility == 'protected' || !$protected && $method->visibility != 'protected'): ?>
<tr<?= $method->definedBy != $type->name ? ' class="inherited"' : '' ?> id="<?= $method->name ?>()">
<td><?= $this->context->subjectLink($method, $method->name.'()') ?></td>
<td><?= $renderer->createSubjectLink($method, $method->name.'()') ?></td>
<td><?= ApiMarkdown::process($method->shortDescription, $method->definedBy, true) ?></td>
<td><?= $this->context->typeLink($method->definedBy, $type) ?></td>
<td><?= $renderer->createTypeLink($method->definedBy, $type) ?></td>
</tr>
<?php endif; ?>
<?php endforeach; ?>
......
......@@ -8,8 +8,11 @@ use yii\helpers\ArrayHelper;
/**
* @var ClassDoc|TraitDoc $type
* @var yii\web\View $this
* @var \yii\apidoc\templates\html\ApiRenderer $renderer
*/
$renderer = $this->context;
$properties = $type->getNativeProperties();
if (empty($properties)) {
return;
......@@ -33,7 +36,7 @@ ArrayHelper::multisort($properties, 'name');
</span>
</div>
<div class="signature"><?php echo $this->context->renderPropertySignature($property); ?></div>
<div class="signature"><?php echo $renderer->renderPropertySignature($property); ?></div>
<p><?= ApiMarkdown::process($property->description, $type) ?></p>
......
......@@ -9,8 +9,11 @@ use yii\helpers\ArrayHelper;
* @var ClassDoc|TraitDoc $type
* @var boolean $protected
* @var yii\web\View $this
* @var \yii\apidoc\templates\html\ApiRenderer $renderer
*/
$renderer = $this->context;
if ($protected && count($type->getProtectedProperties()) == 0 || !$protected && count($type->getPublicProperties()) == 0) {
return;
} ?>
......@@ -36,10 +39,10 @@ ArrayHelper::multisort($properties, 'name');
foreach($properties as $property): ?>
<?php if($protected && $property->visibility == 'protected' || !$protected && $property->visibility != 'protected'): ?>
<tr<?= $property->definedBy != $type->name ? ' class="inherited"' : '' ?> id="<?= $property->name ?>">
<td><?= $this->context->subjectLink($property) ?></td>
<td><?= $this->context->typeLink($property->types) ?></td>
<td><?= $renderer->createSubjectLink($property) ?></td>
<td><?= $renderer->createTypeLink($property->types) ?></td>
<td><?= ApiMarkdown::process($property->shortDescription, $property->definedBy, true) ?></td>
<td><?= $this->context->typeLink($property->definedBy) ?></td>
<td><?= $renderer->createTypeLink($property->definedBy) ?></td>
</tr>
<?php endif; ?>
<?php endforeach; ?>
......
......@@ -7,7 +7,7 @@ use yii\apidoc\models\TraitDoc;
/**
* @var ClassDoc|InterfaceDoc|TraitDoc $type
* @var yii\web\View $this
* @var \yii\apidoc\templates\html\Renderer $renderer
* @var \yii\apidoc\templates\html\ApiRenderer $renderer
*/
$renderer = $this->context;
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\apidoc\templates\offline\assets;
use yii\web\View;
/**
* The asset bundle for the offline template.
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class AssetBundle extends \yii\web\AssetBundle
{
public $sourcePath = '@yii/apidoc/templates/offline/assets/css';
public $css = [
'api.css',
'style.css',
];
public $depends = [
'yii\web\JqueryAsset',
];
public $jsOptions = [
'position' => View::POS_HEAD,
];
}
pre {
color: #000000;
background-color: #FFF5E6;
font-family: "courier new", "times new roman", monospace;
line-height: 1.3em;
/* Put a nice border around it. */
padding: 1px;
width: 90%;
/* Don't wrap its contents, and show scrollbars. */
/* white-space: nowrap;*/
overflow: auto;
/* Stop after about 24 lines, and just show a scrollbar. */
/* max-height: 24em; */
margin: 5px;
padding-left: 20px;
border: 1px solid #FFE6BF;
border-left: 6px solid #FFE6BF;
}
code {
color: #000000;
background-color: #FFF5E6;
padding: 1px;
}
div.code {
display: none;
color: #000000;
background-color: #FFF5E6;
font-family: "courier new", "times new roman", monospace;
line-height: 1.3em;
/* Put a nice border around it. */
padding: 1px;
width: 90%;
/* Don't wrap its contents, and show scrollbars. */
/* white-space: nowrap;*/
overflow: auto;
/* Stop after about 24 lines, and just show a scrollbar. */
/* max-height: 24em; */
margin: 5px;
padding-left: 20px;
border-left: 6px solid #FFE6BF;
}
table.summaryTable {
background: #E6ECFF;
border-collapse: collapse;
width: 100%;
}
table.summaryTable th, table.summaryTable td {
border: 1px #BFCFFF solid;
padding: 0.2em;
}
table.summaryTable th {
background: #CCD9FF;
text-align: left;
}
#nav {
padding: 3px;
margin: 0 0 10px 0;
border-top: 1px #BFCFFF solid;
}
#classDescription {
padding: 5px;
margin: 10px 0 20px 0;
border-bottom: 1px solid #BFCFFF;
}
.detailHeader {
font-weight: bold;
font-size: 12pt;
margin: 30px 0 5px 0;
border-bottom: 1px solid #BFCFFF;
}
.detailHeaderTag {
font-weight: normal;
font-size: 10pt;
}
.signature, .signature2 {
padding: 3px;
color: #000000;
font-family: "courier new", "times new roman", monospace;
line-height: 1.3em;
}
.signature {
margin: 10px 0 10px 0;
background: #E6ECFF;
border: 1px #BFCFFF solid;
}
.paramNameCol {
width: 12%;
font-weight: bold;
}
.paramTypeCol {
width: 12%;
}
.sourceCode {
margin: 5px 0;
padding:5px;
background:#FFF5E6;
}
\ No newline at end of file
body
{
}
body, div, span, p, input
{
font-family: Verdana, Arial, sans-serif;
font-size: 10pt;
color: #333333;
}
#apiPage {
}
#apiHeader {
padding: 3px;
color: white;
background: #6078BF;
margin-bottom: 5px;
font-weight: bold;
}
#apiHeader a {
color: white;
}
#apiFooter {
margin-top: 5px;
padding: 3px;
border-top: 1px solid #BFCFFF;
text-align: center;
}
<?php
use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\InterfaceDoc;
use yii\apidoc\models\TraitDoc;
/**
* @var ClassDoc[]|InterfaceDoc[]|TraitDoc[] $types
* @var yii\web\View $this
*/
?><h1>Class Reference</h1>
<table class="summaryTable docIndex">
<colgroup>
<col class="col-package" />
<col class="col-class" />
<col class="col-description" />
</colgroup>
<tr>
<th>Class</th>
<th>Description</th>
</tr>
<?php
ksort($types);
foreach($types as $i=>$class):
?>
<tr>
<td><?= $this->context->typeLink($class, $class->name) ?></td>
<td><?= \yii\apidoc\helpers\Markdown::process($class->shortDescription, $class) ?></td>
</tr>
<?php endforeach; ?>
</table>
<?php
/**
* @var yii\web\View $this
*/
\yii\apidoc\templates\offline\assets\AssetBundle::register($this);
$this->beginPage();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="language" content="en" />
<?php $this->head(); ?>
<title><?php echo $this->context->pageTitle; ?></title>
</head>
<body>
<?php $this->beginBody(); ?>
<div id="apiPage">
<div id="apiHeader">
<a href="http://www.yiiframework.com">Yii Framework</a> v<?php echo Yii::getVersion(); ?> Class Reference
</div><!-- end of header -->
<div id="content">
<?php echo $content; ?>
</div><!-- end of content -->
<div id="apiFooter">
<p>&copy; 2008-2013 by <a href="http://www.yiisoft.com">Yii Software LLC</a></p>
<p>All Rights Reserved.</p>
</div><!-- end of footer -->
<script type="text/javascript">
/*<![CDATA[*/
$("a.toggle").on('click', function() {
var $this = $(this);
if ($this.hasClass('properties-hidden')) {
$this.text($this.text().replace(/Show/,'Hide'));
$this.parents(".summary").find(".inherited").show();
$this.removeClass('properties-hidden');
} else {
$this.text($this.text().replace(/Hide/,'Show'));
$this.parents(".summary").find(".inherited").hide();
$this.addClass('properties-hidden');
}
return false;
});
/*
$(".sourceCode a.show").toggle(function(){
$(this).text($(this).text().replace(/show/,'hide'));
$(this).parents(".sourceCode").find("div.code").show();
},function(){
$(this).text($(this).text().replace(/hide/,'show'));
$(this).parents(".sourceCode").find("div.code").hide();
});
$("a.sourceLink").click(function(){
$(this).attr('target','_blank');
});
*/
/*]]>*/
</script>
</div><!-- end of page -->
<?php $this->endBody(); ?>
</body>
</html>
<?php $this->endPage(); ?>
......@@ -17,24 +17,23 @@ use yii\helpers\Console;
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class Renderer extends \yii\apidoc\templates\html\Renderer
class ApiRenderer extends \yii\apidoc\templates\html\ApiRenderer
{
public $apiLayout = false;
public $layout = false;
public $indexView = '@yii/apidoc/templates/online/views/index.php';
public $pageTitle = 'Yii Framework 2.0 API Documentation';
/**
* Renders a given [[Context]].
*
* @param Context $context the api documentation context to render.
* @param Controller $controller the apidoc controller instance. Can be used to control output.
* @inheritdoc
*/
public function renderApi($context, $controller)
public function render($context, $targetDir)
{
parent::renderApi($context, $controller);
$dir = Yii::getAlias($this->targetDir);
$controller->stdout("writing packages file...");
parent::render($context, $targetDir);
if ($this->controller !== null) {
$this->controller->stdout("writing packages file...");
}
$packages = [];
$notNamespaced = [];
foreach(array_merge($context->classes, $context->interfaces, $context->traits) as $type) {
......@@ -50,17 +49,19 @@ class Renderer extends \yii\apidoc\templates\html\Renderer
foreach($packages as $name => $classes) {
sort($packages[$name]);
}
file_put_contents($dir . '/packages.txt', serialize($packages));
$controller->stdout('done.' . PHP_EOL, Console::FG_GREEN);
file_put_contents($targetDir . '/packages.txt', serialize($packages));
if ($this->controller !== null) {
$this->controller->stdout('done.' . PHP_EOL, Console::FG_GREEN);
}
}
public function generateUrl($typeName)
public function generateApiUrl($typeName)
{
return strtolower(str_replace('\\', '-', $typeName));
}
protected function generateFileName($typeName)
{
return $this->generateUrl($typeName) . '.html';
return $this->generateApiUrl($typeName) . '.html';
}
}
\ No newline at end of file
The `online` API doc template
=============================
This template is used to generate the Yii framework API docs for yiiframework.com.
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment