Commit 55f9111f by Carsten Brandt

markdown support and links

parent b9c1eff3
<?php
/**
*
*
* @author Carsten Brandt <mail@cebe.cc>
*/
namespace yii\apidoc\helpers;
use phpDocumentor\Reflection\DocBlock\Type\Collection;
use yii\apidoc\models\MethodDoc;
use yii\apidoc\models\TypeDoc;
use yii\apidoc\templates\BaseRenderer;
use yii\helpers\Html;
class Markdown extends \yii\helpers\Markdown
{
/**
* @var BaseRenderer
*/
public static $renderer;
/**
* Converts markdown into HTML
*
* @param string $content
* @param TypeDoc $context
* @return string
*/
public static function process($content, $context)
{
$content = trim(parent::process($content, []));
if (!strncmp($content, '<p>', 3) && substr($content, -4, 4) == '</p>') {
$content = substr($content, 3, -4);
}
$content = preg_replace_callback('/\[\[([\w\d\\\\\(\):]+)(\|[\w\d ]*)?\]\]/xm', function($matches) use ($context) {
$object = $matches[1];
$title = (empty($matches[2]) || $matches[2] == '|') ? null : substr($matches[2], 1);
if (($pos = strpos($object, '::')) !== false) {
$typeName = substr($object, 0, $pos);
$subjectName = substr($object, $pos + 2);
// Collection resolves relative types
$typeName = (new Collection([$typeName], $context->phpDocContext))->__toString();
$type = static::$renderer->context->getType($typeName);
if ($type === null) {
return '<span style="background: #f00;">' . $typeName . '::' . $subjectName . '</span>';
} else {
if (($subject = $type->findSubject($subjectName)) !== null) {
if ($title === null) {
$title = $type->name . '::' . $subject->name;
if ($subject instanceof MethodDoc) {
$title .= '()';
}
}
return static::$renderer->subjectLink($subject, $title);
} else {
return '<span style="background: #ff0;">' . $type->name . '</span><span style="background: #f00;">::' . $subjectName . '</span>';
}
}
} elseif (($subject = $context->findSubject($object)) !== null) {
return static::$renderer->subjectLink($subject, $title);
}
// Collection resolves relative types
$object = (new Collection([$object], $context->phpDocContext))->__toString();
if (($type = static::$renderer->context->getType($object)) !== null) {
return static::$renderer->typeLink($type, $title);
}
return '<span style="background: #f00;">' . $object . '</span>';
}, $content);
return $content;
}
}
\ No newline at end of file
...@@ -18,6 +18,11 @@ use yii\base\Object; ...@@ -18,6 +18,11 @@ use yii\base\Object;
*/ */
class BaseDoc extends Object class BaseDoc extends Object
{ {
/**
* @var \phpDocumentor\Reflection\DocBlock\Context
*/
public $phpDocContext;
public $name; public $name;
public $sourceFile; public $sourceFile;
...@@ -55,9 +60,11 @@ class BaseDoc extends Object ...@@ -55,9 +60,11 @@ class BaseDoc extends Object
$docblock = $reflector->getDocBlock(); $docblock = $reflector->getDocBlock();
if ($docblock !== null) { if ($docblock !== null) {
$this->shortDescription = $docblock->getShortDescription(); $this->shortDescription = ucfirst($docblock->getShortDescription());
$this->description = $docblock->getLongDescription(); $this->description = $docblock->getLongDescription();
$this->phpDocContext = $docblock->getContext();
$this->tags = $docblock->getTags(); $this->tags = $docblock->getTags();
foreach($this->tags as $i => $tag) { foreach($this->tags as $i => $tag) {
if ($tag instanceof SinceTag) { if ($tag instanceof SinceTag) {
......
...@@ -34,6 +34,24 @@ class ClassDoc extends TypeDoc ...@@ -34,6 +34,24 @@ class ClassDoc extends TypeDoc
public $constants = []; public $constants = [];
public function findSubject($subjectName)
{
if (($subject = parent::findSubject($subjectName)) !== null) {
return $subject;
}
foreach($this->events as $name => $event) {
if ($subjectName == $name) {
return $event;
}
}
foreach($this->constants as $name => $constant) {
if ($subjectName == $name) {
return $constant;
}
}
return null;
}
/** /**
* @return EventDoc[] * @return EventDoc[]
*/ */
......
...@@ -60,7 +60,7 @@ class FunctionDoc extends BaseDoc ...@@ -60,7 +60,7 @@ class FunctionDoc extends BaseDoc
if (!isset($this->params[$paramName])) { if (!isset($this->params[$paramName])) {
echo 'undefined parameter documented: ' . $paramName . ' in ' . $this->name . "\n"; // todo add this to a log file echo 'undefined parameter documented: ' . $paramName . ' in ' . $this->name . "\n"; // todo add this to a log file
} }
$this->params[$paramName]->description = $tag->getDescription(); $this->params[$paramName]->description = ucfirst($tag->getDescription());
$this->params[$paramName]->type = $tag->getType(); $this->params[$paramName]->type = $tag->getType();
$this->params[$paramName]->types = $tag->getTypes(); $this->params[$paramName]->types = $tag->getTypes();
unset($this->tags[$i]); unset($this->tags[$i]);
......
...@@ -30,6 +30,30 @@ class TypeDoc extends BaseDoc ...@@ -30,6 +30,30 @@ class TypeDoc extends BaseDoc
public $namespace; public $namespace;
public function findSubject($subjectName)
{
if ($subjectName[0] != '$') {
foreach($this->methods as $name => $method) {
if (rtrim($subjectName, '()') == $name) {
return $method;
}
}
}
if (substr($subjectName, -2, 2) == '()') {
return null;
}
if ($this->properties === null) {
return null;
}
foreach($this->properties as $name => $property) {
if (ltrim($subjectName, '$') == ltrim($name, '$')) {
return $property;
}
}
return null;
}
/** /**
* @return MethodDoc[] * @return MethodDoc[]
*/ */
......
...@@ -8,11 +8,16 @@ ...@@ -8,11 +8,16 @@
namespace yii\apidoc\templates; namespace yii\apidoc\templates;
use Yii; 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\base\Component;
use yii\console\Controller; use yii\console\Controller;
use yii\apidoc\models\Context;
use yii\web\AssetManager;
use yii\web\View;
/** /**
* Base class for all API documentation renderers * Base class for all API documentation renderers
...@@ -23,10 +28,32 @@ use yii\web\View; ...@@ -23,10 +28,32 @@ use yii\web\View;
abstract class BaseRenderer extends Component abstract class BaseRenderer extends Component
{ {
/** /**
* @var Context the [[Context]] currently being rendered.
*/
public $context;
/**
* Renders a given [[Context]]. * Renders a given [[Context]].
* *
* @param Context $context the api documentation context to render. * @param Context $context the api documentation context to render.
* @param Controller $controller the apidoc controller instance. Can be used to control output. * @param Controller $controller the apidoc controller instance. Can be used to control output.
*/ */
public abstract function render($context, $controller); public abstract function render($context, $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
*/
public abstract function subjectLink($subject, $title = null);
} }
\ No newline at end of file
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
namespace yii\apidoc\templates\html; namespace yii\apidoc\templates\html;
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\BaseDoc; use yii\apidoc\models\BaseDoc;
use yii\apidoc\models\ConstDoc; use yii\apidoc\models\ConstDoc;
use yii\apidoc\models\EventDoc; use yii\apidoc\models\EventDoc;
...@@ -55,14 +56,16 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface ...@@ -55,14 +56,16 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
*/ */
public $indexView = '@yii/apidoc/templates/html/views/index.php'; public $indexView = '@yii/apidoc/templates/html/views/index.php';
/** /**
* @var Context the [[Context]] currently being rendered.
*/
protected $context;
/**
* @var View * @var View
*/ */
private $_view; private $_view;
public function init()
{
Markdown::$renderer = $this;
}
/** /**
* @return View the view instance * @return View the view instance
*/ */
...@@ -179,8 +182,12 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface ...@@ -179,8 +182,12 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
public function subjectLink($subject, $title = null) public function subjectLink($subject, $title = null)
{ {
if ($title === null) { if ($title === null) {
if ($subject instanceof MethodDoc) {
$title = $subject->name . '()';
} else {
$title = $subject->name; $title = $subject->name;
} }
}
if (($type = $this->context->getType($subject->definedBy)) === null) { if (($type = $this->context->getType($subject->definedBy)) === null) {
return $subject->name; return $subject->name;
} else { } else {
......
<?php <?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc; use yii\apidoc\models\ClassDoc;
/** /**
* @var ClassDoc $type * @var ClassDoc $type
...@@ -27,7 +28,7 @@ if (empty($type->constants)) { ...@@ -27,7 +28,7 @@ if (empty($type->constants)) {
<tr<?= $constant->definedBy != $type->name ? ' class="inherited"' : '' ?> id="<?= $constant->name ?>"> <tr<?= $constant->definedBy != $type->name ? ' class="inherited"' : '' ?> id="<?= $constant->name ?>">
<td><?= $constant->name ?></td> <td><?= $constant->name ?></td>
<td><?= $constant->value ?></td> <td><?= $constant->value ?></td>
<td><?= nl2br($constant->shortDescription . "\n" . $constant->description) ?></td> <td><?= Markdown::process($constant->shortDescription . "\n" . $constant->description, $type) ?></td>
<td><?= $this->context->typeLink($constant->definedBy) ?></td> <td><?= $this->context->typeLink($constant->definedBy) ?></td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
......
<?php <?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc; use yii\apidoc\models\ClassDoc;
/** /**
* @var ClassDoc $type * @var ClassDoc $type
...@@ -27,7 +28,7 @@ if (empty($events)) { ...@@ -27,7 +28,7 @@ if (empty($events)) {
<?php echo $event->trigger->signature; ?> <?php echo $event->trigger->signature; ?>
</div>*/ ?> </div>*/ ?>
<p><?php echo $event->description; ?></p> <p><?= Markdown::process($event->description, $type); ?></p>
<?= $this->render('seeAlso', ['object' => $event]); ?> <?= $this->render('seeAlso', ['object' => $event]); ?>
......
<?php <?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc; use yii\apidoc\models\ClassDoc;
/** /**
* @var ClassDoc $type * @var ClassDoc $type
...@@ -28,7 +29,7 @@ if (empty($type->events)) { ...@@ -28,7 +29,7 @@ if (empty($type->events)) {
<td><?= $this->context->subjectLink($event) ?></td> <td><?= $this->context->subjectLink($event) ?></td>
<td><?= $this->context->typeLink($event->types) ?></td> <td><?= $this->context->typeLink($event->types) ?></td>
<td> <td>
<?= $event->shortDescription ?> <?= Markdown::process($event->shortDescription, $type) ?>
<?php if(!empty($event->since)): ?> <?php if(!empty($event->since)): ?>
(available since version <?php echo $event->since; ?>) (available since version <?php echo $event->since; ?>)
<?php endif; ?> <?php endif; ?>
......
<?php <?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc; use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\TraitDoc; use yii\apidoc\models\TraitDoc;
/** /**
...@@ -36,14 +37,14 @@ if (empty($methods)) { ...@@ -36,14 +37,14 @@ if (empty($methods)) {
<tr> <tr>
<td class="paramNameCol"><?= $param->name ?></td> <td class="paramNameCol"><?= $param->name ?></td>
<td class="paramTypeCol"><?= $this->context->typeLink($param->types) ?></td> <td class="paramTypeCol"><?= $this->context->typeLink($param->types) ?></td>
<td class="paramDescCol"><?= $param->description ?></td> <td class="paramDescCol"><?= Markdown::process($param->description, $type) ?></td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
<?php if(!empty($method->return)): ?> <?php if(!empty($method->return)): ?>
<tr> <tr>
<td class="paramNameCol"><?= '{return}'; ?></td> <td class="paramNameCol"><?= '{return}'; ?></td>
<td class="paramTypeCol"><?= $this->context->typeLink($method->returnTypes); ?></td> <td class="paramTypeCol"><?= $this->context->typeLink($method->returnTypes); ?></td>
<td class="paramDescCol"><?= $method->return; ?></td> <td class="paramDescCol"><?= Markdown::process($method->return, $type); ?></td>
</tr> </tr>
<?php endif; ?> <?php endif; ?>
<?php endif; ?> <?php endif; ?>
...@@ -51,8 +52,8 @@ if (empty($methods)) { ...@@ -51,8 +52,8 @@ if (empty($methods)) {
<!-- --><?php //$this->renderPartial('sourceCode',array('object'=>$method)); ?> <!-- --><?php //$this->renderPartial('sourceCode',array('object'=>$method)); ?>
<p><strong><?= $method->shortDescription ?></strong></p> <p><?= Markdown::process($method->shortDescription, $type) ?></strong></p>
<p><?= nl2br($method->description) ?></p> <p><?= Markdown::process($method->description, $type) ?></p>
<?= $this->render('seeAlso', ['object' => $method]); ?> <?= $this->render('seeAlso', ['object' => $method]); ?>
......
<?php <?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc; use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\InterfaceDoc; use yii\apidoc\models\InterfaceDoc;
use yii\apidoc\models\TraitDoc; use yii\apidoc\models\TraitDoc;
...@@ -28,13 +29,13 @@ if ($protected && count($type->getProtectedMethods()) == 0 || !$protected && cou ...@@ -28,13 +29,13 @@ if ($protected && count($type->getProtectedMethods()) == 0 || !$protected && cou
<th>Method</th><th>Description</th><th>Defined By</th> <th>Method</th><th>Description</th><th>Defined By</th>
</tr> </tr>
<?php foreach($type->methods as $method): ?> <?php foreach($type->methods as $method): ?>
<?php if($protected && $method->visibility == 'protected' || !$protected && $method->visibility != 'protected'): ?> <?php if($protected && $method->visibility == 'protected' || !$protected && $method->visibility != 'protected'): ?>
<tr<?= $method->definedBy != $type->name ? ' class="inherited"' : '' ?> id="<?= $method->name ?>()"> <tr<?= $method->definedBy != $type->name ? ' class="inherited"' : '' ?> id="<?= $method->name ?>()">
<td><?= $this->context->subjectLink($method, $method->name.'()') ?></td> <td><?= $this->context->subjectLink($method, $method->name.'()') ?></td>
<td><?= $method->shortDescription ?></td> <td><?= Markdown::process($method->shortDescription, $type) ?></td>
<td><?= $this->context->typeLink($method->definedBy) ?></td> <td><?= $this->context->typeLink($method->definedBy, $type) ?></td>
</tr> </tr>
<?php endif; ?> <?php endif; ?>
<?php endforeach; ?> <?php endforeach; ?>
</table> </table>
</div> </div>
\ No newline at end of file
<?php <?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc; use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\TraitDoc; use yii\apidoc\models\TraitDoc;
/** /**
...@@ -31,7 +32,7 @@ if (empty($properties)) { ...@@ -31,7 +32,7 @@ if (empty($properties)) {
<?php echo $this->context->renderPropertySignature($property); ?> <?php echo $this->context->renderPropertySignature($property); ?>
</div> </div>
<p><?= nl2br($property->description) ?></p> <p><?= Markdown::process($property->description, $type) ?></p>
<?= $this->render('seeAlso', ['object' => $property]); ?> <?= $this->render('seeAlso', ['object' => $property]); ?>
......
<?php <?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc; use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\TraitDoc; use yii\apidoc\models\TraitDoc;
/** /**
...@@ -28,14 +29,14 @@ if ($protected && count($type->getProtectedProperties()) == 0 || !$protected && ...@@ -28,14 +29,14 @@ if ($protected && count($type->getProtectedProperties()) == 0 || !$protected &&
<th>Property</th><th>Type</th><th>Description</th><th>Defined By</th> <th>Property</th><th>Type</th><th>Description</th><th>Defined By</th>
</tr> </tr>
<?php foreach($type->properties as $property): ?> <?php foreach($type->properties as $property): ?>
<?php if($protected && $property->visibility == 'protected' || !$protected && $property->visibility != 'protected'): ?> <?php if($protected && $property->visibility == 'protected' || !$protected && $property->visibility != 'protected'): ?>
<tr<?= $property->definedBy != $type->name ? ' class="inherited"' : '' ?> id="<?= $property->name ?>"> <tr<?= $property->definedBy != $type->name ? ' class="inherited"' : '' ?> id="<?= $property->name ?>">
<td><?php echo $this->context->subjectLink($property); ?></td> <td><?= $this->context->subjectLink($property) ?></td>
<td><?php echo $this->context->typeLink($property->types); ?></td> <td><?= $this->context->typeLink($property->types) ?></td>
<td><?php echo $property->shortDescription; ?></td> <td><?= Markdown::process($property->shortDescription, $type) ?></td>
<td><?php echo $this->context->typeLink($property->definedBy); ?></td> <td><?= $this->context->typeLink($property->definedBy) ?></td>
</tr> </tr>
<?php endif; ?> <?php endif; ?>
<?php endforeach; ?> <?php endforeach; ?>
</table> </table>
</div> </div>
\ No newline at end of file
...@@ -9,7 +9,12 @@ $see = []; ...@@ -9,7 +9,12 @@ $see = [];
foreach($object->tags as $tag) { foreach($object->tags as $tag) {
/** @var $tag phpDocumentor\Reflection\DocBlock\Tag\SeeTag */ /** @var $tag phpDocumentor\Reflection\DocBlock\Tag\SeeTag */
if (get_class($tag) == 'phpDocumentor\Reflection\DocBlock\Tag\SeeTag') { if (get_class($tag) == 'phpDocumentor\Reflection\DocBlock\Tag\SeeTag') {
$see[] = $tag->getReference(); $ref = $tag->getReference();
if (strpos($ref, '://') === false) {
$see[] = '[[' . $ref . ']]';
} else {
$see[] = $ref;
}
} }
} }
if (empty($see)) { if (empty($see)) {
...@@ -20,7 +25,7 @@ if (empty($see)) { ...@@ -20,7 +25,7 @@ if (empty($see)) {
<h4>See Also</h4> <h4>See Also</h4>
<ul> <ul>
<?php foreach($see as $ref): ?> <?php foreach($see as $ref): ?>
<li><?= $ref ?></li> <li><?= \yii\apidoc\helpers\Markdown::process($ref, $this->context->context->getType($object->definedBy)) ?></li>
<?php endforeach; ?> <?php endforeach; ?>
</ul> </ul>
</div> </div>
<?php <?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc; use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\InterfaceDoc; use yii\apidoc\models\InterfaceDoc;
use yii\apidoc\models\TraitDoc; use yii\apidoc\models\TraitDoc;
/** /**
* @var ClassDoc|InterfaceDoc|TraitDoc $type * @var ClassDoc|InterfaceDoc|TraitDoc $type
* @var yii\web\View $this * @var yii\web\View $this
* @var \yii\apidoc\components\OfflineRenderer $renderer * @var \yii\apidoc\templates\html\Renderer $renderer
*/ */
$renderer = $this->context; $renderer = $this->context;
...@@ -76,8 +77,8 @@ $renderer = $this->context; ...@@ -76,8 +77,8 @@ $renderer = $this->context;
</table> </table>
<div id="classDescription"> <div id="classDescription">
<strong><?= $type->shortDescription ?></strong> <strong><?= Markdown::process($type->shortDescription, $type) ?></strong>
<p><?= nl2br($type->description) ?></p> <p><?= Markdown::process($type->description, $type) ?></p>
</div> </div>
<a name="properties"></a> <a name="properties"></a>
......
...@@ -17,6 +17,12 @@ pre { ...@@ -17,6 +17,12 @@ pre {
border-left: 6px solid #FFE6BF; border-left: 6px solid #FFE6BF;
} }
code {
color: #000000;
background-color: #FFF5E6;
padding: 1px;
}
div.code { div.code {
display: none; display: none;
color: #000000; color: #000000;
......
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