From 5ede58fef678a9e0f97864251d3483eb6091976d Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Mon, 6 Jan 2014 04:30:50 +0100 Subject: [PATCH] finished the property feature --- extensions/yii/apidoc/models/Context.php | 119 +++++++++++++++++++++- extensions/yii/apidoc/models/FunctionDoc.php | 2 +- extensions/yii/apidoc/models/TypeDoc.php | 19 ---- extensions/yii/apidoc/templates/html/Renderer.php | 25 ++--- 4 files changed, 130 insertions(+), 35 deletions(-) diff --git a/extensions/yii/apidoc/models/Context.php b/extensions/yii/apidoc/models/Context.php index 5378195..4260cbf 100644 --- a/extensions/yii/apidoc/models/Context.php +++ b/extensions/yii/apidoc/models/Context.php @@ -103,10 +103,16 @@ class Context extends Component } } } - // update properties, methods, contants and events of subclasses + // inherit properties, methods, contants and events to subclasses foreach($this->classes as $class) { $this->updateSubclassInheritance($class); } + // add properties from getters and setters + foreach($this->classes as $class) { + $this->handlePropertyFeature($class); + } + + // TODO reference exceptions to methods where they are thrown } /** @@ -138,4 +144,115 @@ class Context extends Component $this->updateSubclassInheritance($subclass); } } + + /** + * Add properties for getters and setters if class is subclass of [[yii\base\Object]]. + * @param ClassDoc $class + */ + protected function handlePropertyFeature($class) + { + if (!$this->isSubclassOf($class, 'yii\base\Object')) { + return; + } + foreach($class->getPublicMethods() as $name => $method) { + if (!strncmp($name, 'get', 3) && $this->paramsOptional($method)) { + $propertyName = '$' . lcfirst(substr($method->name, 3)); + if (isset($class->properties[$propertyName])) { + $property = $class->properties[$propertyName]; + if ($property->getter === null && $property->setter === null) { + echo "Property $propertyName conflicts with a defined getter {$method->name} in {$class->name}."; // TODO log these messages somewhere + } + $property->getter = $method; + } else { + $class->properties[$propertyName] = new PropertyDoc(null, [ + 'name' => $propertyName, + 'definedBy' => $class->name, + 'visibility' => 'public', + 'isStatic' => false, + 'type' => $method->returnType, + 'types' => $method->returnTypes, + 'shortDescription' => (($pos = strpos($method->return, '.')) !== false) ? + substr($method->return, 0, $pos) : $method->return, + 'description' => $method->return, + 'getter' => $method + // TODO set default value + ]); + } + } + if (!strncmp($name, 'set', 3) && $this->paramsOptional($method, 1)) { + $propertyName = '$' . lcfirst(substr($method->name, 3)); + if (isset($class->properties[$propertyName])) { + $property = $class->properties[$propertyName]; + if ($property->getter === null && $property->setter === null) { + echo "Property $propertyName conflicts with a defined setter {$method->name} in {$class->name}."; // TODO log these messages somewhere + } + $property->setter = $method; + } else { + $param = $this->getFirstNotOptionalParameter($method); + $class->properties[$propertyName] = new PropertyDoc(null, [ + 'name' => $propertyName, + 'definedBy' => $class->name, + 'visibility' => 'public', + 'isStatic' => false, + 'type' => $param->type, + 'types' => $param->types, + 'shortDescription' => (($pos = strpos($param->description, '.')) !== false) ? + substr($param->description, 0, $pos) : $param->description, + 'description' => $param->description, + 'setter' => $method + ]); + } + } + } + } + + /** + * @param MethodDoc $method + * @param integer $number number of not optional parameters + * @return bool + */ + private function paramsOptional($method, $number = 0) + { + foreach($method->params as $param) { + if (!$param->isOptional && $number-- <= 0) { + return false; + } + } + return true; + } + + /** + * @param MethodDoc $method + * @return ParamDoc + */ + private function getFirstNotOptionalParameter($method) + { + foreach($method->params as $param) { + if (!$param->isOptional) { + return $param; + } + } + return null; + } + + /** + * @param ClassDoc $classA + * @param ClassDoc $classB + */ + protected function isSubclassOf($classA, $classB) + { + if (is_object($classB)) { + $classB = $classB->name; + } + if ($classA->name == $classB) { + return true; + } + while($classA->parentClass !== null && isset($this->classes[$classA->parentClass])) { + $classA = $this->classes[$classA->parentClass]; + if ($classA->name == $classB) { + return true; + } + } + return false; + } } \ No newline at end of file diff --git a/extensions/yii/apidoc/models/FunctionDoc.php b/extensions/yii/apidoc/models/FunctionDoc.php index 9c7e212..62026a8 100644 --- a/extensions/yii/apidoc/models/FunctionDoc.php +++ b/extensions/yii/apidoc/models/FunctionDoc.php @@ -54,7 +54,7 @@ class FunctionDoc extends BaseDoc $this->exceptions[$tag->getType()] = $tag->getDescription(); unset($this->tags[$i]); } elseif ($tag instanceof PropertyTag) { - // TODO handle property tag + // ignore property tag } elseif ($tag instanceof ParamTag) { $paramName = $tag->getVariableName(); if (!isset($this->params[$paramName])) { diff --git a/extensions/yii/apidoc/models/TypeDoc.php b/extensions/yii/apidoc/models/TypeDoc.php index 5a83383..a4c68d2 100644 --- a/extensions/yii/apidoc/models/TypeDoc.php +++ b/extensions/yii/apidoc/models/TypeDoc.php @@ -178,25 +178,6 @@ class TypeDoc extends BaseDoc if ($methodReflector->getVisibility() != 'private') { $method = new MethodDoc($methodReflector); $method->definedBy = $this->name; - - // TODO only set property when subclass of Object - if (!strncmp($method->name, 'set', 3)) { - $propertyName = lcfirst(substr($method->name, 3)); - if (isset($this->properties[$propertyName])) { - $property = $this->properties[$propertyName]; - if ($property->getter === null && $property->setter === null) { - throw new Exception("Property $propertyName conflicts with a defined setter {$method->name}."); - } - $property->setter = $method; - } else { -// $this->properties[$propertyName] = new PropertyDoc(null, [ -// 'name' => $propertyName, -// // TODO set description and short description -// ]); - } - } elseif (!strncmp($method->name, 'get', 3)) { - // TODO add property - } $this->methods[$method->name] = $method; } } diff --git a/extensions/yii/apidoc/templates/html/Renderer.php b/extensions/yii/apidoc/templates/html/Renderer.php index 2129695..bc53d3a 100644 --- a/extensions/yii/apidoc/templates/html/Renderer.php +++ b/extensions/yii/apidoc/templates/html/Renderer.php @@ -302,20 +302,17 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface */ public function renderPropertySignature($property) { - return $this->typeLink($property->types) . ' ' . $property->name . ' = ' . ($property->defaultValue === null ? 'null' : $property->defaultValue); - // TODO - if(!empty($property->signature)) - return $property->signature; - $sig=''; - if(!empty($property->getter)) - $sig=$property->getter->signature; - if(!empty($property->setter)) - { - if($sig!=='') - $sig.='
'; - $sig.=$property->setter->signature; + if ($property->getter !== null || $property->setter !== null) { + $sig = []; + if ($property->getter !== null) { + $sig[] = $this->renderMethodSignature($property->getter); + } + if ($property->setter !== null) { + $sig[] = $this->renderMethodSignature($property->setter); + } + return implode('
', $sig); } - return $sig; + return $this->typeLink($property->types) . ' ' . $property->name . ' = ' . ($property->defaultValue === null ? 'null' : $property->defaultValue); } /** @@ -334,7 +331,7 @@ abstract class Renderer extends BaseRenderer implements ViewContextInterface return ($method->isReturnByReference ? '&' : '') . ($method->returnType === null ? 'void' : $this->typeLink($method->returnTypes)) - . ' ' . $method->name . '( ' + . ' ' . $this->subjectLink($method, $method->name) . '( ' . implode(', ', $params) . ' )'; }