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;
*/
class BaseDoc extends Object
{
/**
* @var \phpDocumentor\Reflection\DocBlock\Context
*/
public $phpDocContext;
public $name;
public $sourceFile;
......@@ -55,9 +60,11 @@ class BaseDoc extends Object
$docblock = $reflector->getDocBlock();
if ($docblock !== null) {
$this->shortDescription = $docblock->getShortDescription();
$this->shortDescription = ucfirst($docblock->getShortDescription());
$this->description = $docblock->getLongDescription();
$this->phpDocContext = $docblock->getContext();
$this->tags = $docblock->getTags();
foreach($this->tags as $i => $tag) {
if ($tag instanceof SinceTag) {
......
......@@ -34,6 +34,24 @@ class ClassDoc extends TypeDoc
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[]
*/
......
......@@ -60,7 +60,7 @@ class FunctionDoc extends BaseDoc
if (!isset($this->params[$paramName])) {
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]->types = $tag->getTypes();
unset($this->tags[$i]);
......
......@@ -30,6 +30,30 @@ class TypeDoc extends BaseDoc
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[]
*/
......
......@@ -8,11 +8,16 @@
namespace yii\apidoc\templates;
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;
use yii\apidoc\models\Context;
use yii\web\AssetManager;
use yii\web\View;
/**
* Base class for all API documentation renderers
......@@ -23,10 +28,32 @@ use yii\web\View;
abstract class BaseRenderer extends Component
{
/**
* @var Context the [[Context]] currently being rendered.
*/
public $context;
/**
* 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 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 @@
namespace yii\apidoc\templates\html;
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\BaseDoc;
use yii\apidoc\models\ConstDoc;
use yii\apidoc\models\EventDoc;
......@@ -55,14 +56,16 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
*/
public $indexView = '@yii/apidoc/templates/html/views/index.php';
/**
* @var Context the [[Context]] currently being rendered.
*/
protected $context;
/**
* @var View
*/
private $_view;
public function init()
{
Markdown::$renderer = $this;
}
/**
* @return View the view instance
*/
......@@ -179,7 +182,11 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface
public function subjectLink($subject, $title = null)
{
if ($title === null) {
$title = $subject->name;
if ($subject instanceof MethodDoc) {
$title = $subject->name . '()';
} else {
$title = $subject->name;
}
}
if (($type = $this->context->getType($subject->definedBy)) === null) {
return $subject->name;
......
<?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc;
/**
* @var ClassDoc $type
......@@ -27,7 +28,7 @@ if (empty($type->constants)) {
<tr<?= $constant->definedBy != $type->name ? ' class="inherited"' : '' ?> id="<?= $constant->name ?>">
<td><?= $constant->name ?></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>
</tr>
<?php endforeach; ?>
......
<?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc;
/**
* @var ClassDoc $type
......@@ -27,7 +28,7 @@ if (empty($events)) {
<?php echo $event->trigger->signature; ?>
</div>*/ ?>
<p><?php echo $event->description; ?></p>
<p><?= Markdown::process($event->description, $type); ?></p>
<?= $this->render('seeAlso', ['object' => $event]); ?>
......
<?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc;
/**
* @var ClassDoc $type
......@@ -28,7 +29,7 @@ if (empty($type->events)) {
<td><?= $this->context->subjectLink($event) ?></td>
<td><?= $this->context->typeLink($event->types) ?></td>
<td>
<?= $event->shortDescription ?>
<?= Markdown::process($event->shortDescription, $type) ?>
<?php if(!empty($event->since)): ?>
(available since version <?php echo $event->since; ?>)
<?php endif; ?>
......
<?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\TraitDoc;
/**
......@@ -36,14 +37,14 @@ if (empty($methods)) {
<tr>
<td class="paramNameCol"><?= $param->name ?></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>
<?php endforeach; ?>
<?php if(!empty($method->return)): ?>
<tr>
<td class="paramNameCol"><?= '{return}'; ?></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>
<?php endif; ?>
<?php endif; ?>
......@@ -51,8 +52,8 @@ if (empty($methods)) {
<!-- --><?php //$this->renderPartial('sourceCode',array('object'=>$method)); ?>
<p><strong><?= $method->shortDescription ?></strong></p>
<p><?= nl2br($method->description) ?></p>
<p><?= Markdown::process($method->shortDescription, $type) ?></strong></p>
<p><?= Markdown::process($method->description, $type) ?></p>
<?= $this->render('seeAlso', ['object' => $method]); ?>
......
<?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\InterfaceDoc;
use yii\apidoc\models\TraitDoc;
......@@ -28,13 +29,13 @@ if ($protected && count($type->getProtectedMethods()) == 0 || !$protected && cou
<th>Method</th><th>Description</th><th>Defined By</th>
</tr>
<?php foreach($type->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><?= $method->shortDescription ?></td>
<td><?= $this->context->typeLink($method->definedBy) ?></td>
</tr>
<?php endif; ?>
<?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><?= Markdown::process($method->shortDescription, $type) ?></td>
<td><?= $this->context->typeLink($method->definedBy, $type) ?></td>
</tr>
<?php endif; ?>
<?php endforeach; ?>
</table>
</div>
\ No newline at end of file
<?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\TraitDoc;
/**
......@@ -31,7 +32,7 @@ if (empty($properties)) {
<?php echo $this->context->renderPropertySignature($property); ?>
</div>
<p><?= nl2br($property->description) ?></p>
<p><?= Markdown::process($property->description, $type) ?></p>
<?= $this->render('seeAlso', ['object' => $property]); ?>
......
<?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\TraitDoc;
/**
......@@ -28,14 +29,14 @@ if ($protected && count($type->getProtectedProperties()) == 0 || !$protected &&
<th>Property</th><th>Type</th><th>Description</th><th>Defined By</th>
</tr>
<?php foreach($type->properties as $property): ?>
<?php if($protected && $property->visibility == 'protected' || !$protected && $property->visibility != 'protected'): ?>
<tr<?= $property->definedBy != $type->name ? ' class="inherited"' : '' ?> id="<?= $property->name ?>">
<td><?php echo $this->context->subjectLink($property); ?></td>
<td><?php echo $this->context->typeLink($property->types); ?></td>
<td><?php echo $property->shortDescription; ?></td>
<td><?php echo $this->context->typeLink($property->definedBy); ?></td>
</tr>
<?php endif; ?>
<?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><?= Markdown::process($property->shortDescription, $type) ?></td>
<td><?= $this->context->typeLink($property->definedBy) ?></td>
</tr>
<?php endif; ?>
<?php endforeach; ?>
</table>
</div>
\ No newline at end of file
......@@ -9,7 +9,12 @@ $see = [];
foreach($object->tags as $tag) {
/** @var $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)) {
......@@ -20,7 +25,7 @@ if (empty($see)) {
<h4>See Also</h4>
<ul>
<?php foreach($see as $ref): ?>
<li><?= $ref ?></li>
<li><?= \yii\apidoc\helpers\Markdown::process($ref, $this->context->context->getType($object->definedBy)) ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php
use yii\apidoc\helpers\Markdown;
use yii\apidoc\models\ClassDoc;
use yii\apidoc\models\InterfaceDoc;
use yii\apidoc\models\TraitDoc;
/**
* @var ClassDoc|InterfaceDoc|TraitDoc $type
* @var yii\web\View $this
* @var \yii\apidoc\components\OfflineRenderer $renderer
* @var \yii\apidoc\templates\html\Renderer $renderer
*/
$renderer = $this->context;
......@@ -76,8 +77,8 @@ $renderer = $this->context;
</table>
<div id="classDescription">
<strong><?= $type->shortDescription ?></strong>
<p><?= nl2br($type->description) ?></p>
<strong><?= Markdown::process($type->shortDescription, $type) ?></strong>
<p><?= Markdown::process($type->description, $type) ?></p>
</div>
<a name="properties"></a>
......
......@@ -17,6 +17,12 @@ pre {
border-left: 6px solid #FFE6BF;
}
code {
color: #000000;
background-color: #FFF5E6;
padding: 1px;
}
div.code {
display: none;
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