Improved documentation comments
[kohana-userguide.git] / classes / Kohana / Kodoc / Class.php
blob9ef9b16a14a99d2a1fb2497393c57b0db7104731
1 <?php defined('SYSPATH') or die('No direct script access.');
2 /**
3 * Class documentation generator.
5 * @package Kohana/Userguide
6 * @category Base
7 * @author Kohana Team
8 * @copyright (c) 2008-2013 Kohana Team
9 * @license http://kohanaframework.org/license
11 class Kohana_Kodoc_Class extends Kodoc {
13 /**
14 * @var ReflectionClass The ReflectionClass for this class
16 public $class;
18 /**
19 * @var string modifiers like abstract, final
21 public $modifiers;
23 /**
24 * @var string description of the class from the comment
26 public $description;
28 /**
29 * @var array array of tags, retrieved from the comment
31 public $tags = array();
33 /**
34 * @var array array of this classes constants
36 public $constants = array();
38 /**
39 * @var array Parent classes/interfaces of this class/interface
41 public $parents = array();
43 /**
44 * Loads a class and uses [reflection](http://php.net/reflection) to parse
45 * the class. Reads the class modifiers, constants and comment. Parses the
46 * comment to find the description and tags.
48 * @param string Class name
49 * @return void
51 public function __construct($class)
53 $this->class = new ReflectionClass($class);
55 if ($modifiers = $this->class->getModifiers())
57 $this->modifiers = '<small>'.implode(' ', Reflection::getModifierNames($modifiers)).'</small> ';
60 $this->constants = $this->class->getConstants();
62 // If ReflectionClass::getParentClass() won't work if the class in
63 // question is an interface
64 if ($this->class->isInterface())
66 $this->parents = $this->class->getInterfaces();
68 else
70 $parent = $this->class;
72 while ($parent = $parent->getParentClass())
74 $this->parents[] = $parent;
78 if ( ! $comment = $this->class->getDocComment())
80 foreach ($this->parents as $parent)
82 if ($comment = $parent->getDocComment())
84 // Found a description for this class
85 break;
90 list($this->description, $this->tags) = Kodoc::parse($comment, FALSE);
93 /**
94 * Gets the constants of this class as HTML.
96 * @return array
98 public function constants()
100 $result = array();
102 foreach ($this->constants as $name => $value)
104 $result[$name] = Debug::vars($value);
107 return $result;
111 * Get the description of this class as HTML. Includes a warning when the
112 * class or one of its parents could not be found.
114 * @return string HTML
116 public function description()
118 $result = $this->description;
120 // If this class extends Kodoc_Missing, add a warning about possible
121 // incomplete documentation
122 foreach ($this->parents as $parent)
124 if ($parent->name == 'Kodoc_Missing')
126 $result .= "[!!] **This class, or a class parent, could not be
127 found or loaded. This could be caused by a missing
128 module or other dependancy. The documentation for
129 class may not be complete!**";
133 return Kodoc_Markdown::markdown($result);
137 * Gets a list of the class properties as [Kodoc_Property] objects.
139 * @return array
141 public function properties()
143 $props = $this->class->getProperties();
145 $defaults = $this->class->getDefaultProperties();
147 usort($props, array($this,'_prop_sort'));
149 foreach ($props as $key => $property)
151 // Create Kodoc Properties for each property
152 $props[$key] = new Kodoc_Property($this->class->name, $property->name, Arr::get($defaults, $property->name));
155 return $props;
158 protected function _prop_sort($a, $b)
160 // If one property is public, and the other is not, it goes on top
161 if ($a->isPublic() AND ( ! $b->isPublic()))
162 return -1;
163 if ($b->isPublic() AND ( ! $a->isPublic()))
164 return 1;
166 // If one property is protected and the other is private, it goes on top
167 if ($a->isProtected() AND $b->isPrivate())
168 return -1;
169 if ($b->isProtected() AND $a->isPrivate())
170 return 1;
172 // Otherwise just do alphabetical
173 return strcmp($a->name, $b->name);
177 * Gets a list of the class properties as [Kodoc_Method] objects.
179 * @return array
181 public function methods()
183 $methods = $this->class->getMethods();
185 usort($methods, array($this,'_method_sort'));
187 foreach ($methods as $key => $method)
189 $methods[$key] = new Kodoc_Method($this->class->name, $method->name);
192 return $methods;
196 * Sort methods based on their visibility and declaring class based on:
198 * * methods will be sorted public, protected, then private.
199 * * methods that are declared by an ancestor will be after classes
200 * declared by the current class
201 * * lastly, they will be sorted alphabetically
204 protected function _method_sort($a, $b)
206 // If one method is public, and the other is not, it goes on top
207 if ($a->isPublic() AND ( ! $b->isPublic()))
208 return -1;
209 if ($b->isPublic() AND ( ! $a->isPublic()))
210 return 1;
212 // If one method is protected and the other is private, it goes on top
213 if ($a->isProtected() AND $b->isPrivate())
214 return -1;
215 if ($b->isProtected() AND $a->isPrivate())
216 return 1;
218 // The methods have the same visibility, so check the declaring class depth:
222 echo Debug::vars('a is '.$a->class.'::'.$a->name,'b is '.$b->class.'::'.$b->name,
223 'are the classes the same?', $a->class == $b->class,'if they are, the result is:',strcmp($a->name, $b->name),
224 'is a this class?', $a->name == $this->class->name,-1,
225 'is b this class?', $b->name == $this->class->name,1,
226 'otherwise, the result is:',strcmp($a->class, $b->class)
230 // If both methods are defined in the same class, just compare the method names
231 if ($a->class == $b->class)
232 return strcmp($a->name, $b->name);
234 // If one of them was declared by this class, it needs to be on top
235 if ($a->name == $this->class->name)
236 return -1;
237 if ($b->name == $this->class->name)
238 return 1;
240 // Otherwise, get the parents of each methods declaring class, then compare which function has more "ancestors"
241 $adepth = 0;
242 $bdepth = 0;
244 $parent = $a->getDeclaringClass();
247 $adepth++;
249 while ($parent = $parent->getParentClass());
251 $parent = $b->getDeclaringClass();
254 $bdepth++;
256 while ($parent = $parent->getParentClass());
258 return $bdepth - $adepth;
262 * Get the tags of this class as HTML.
264 * @return array
266 public function tags()
268 $result = array();
270 foreach ($this->tags as $name => $set)
272 foreach ($set as $text)
274 $result[$name][] = Kodoc::format_tag($name, $text);
278 return $result;
281 } // End Kodoc_Class