Ticket #35065: docblocks.diff
File docblocks.diff, 98.4 KB (added by , 9 years ago) |
---|
-
tests/phpunit/tests/docs/docblocks.php
1 <?php 2 3 class Tests_DocBlocks extends WP_UnitTestCase { 4 5 public function setUp() { 6 7 if ( ! is_callable( 'spl_autoload_register' ) ) { 8 $this->markTestSkipped( 'Autoload is not available' ); 9 } 10 11 parent::setUp(); 12 13 spl_autoload_register( array( $this, 'autoloader' ) ); 14 15 } 16 17 public function autoloader( $class ) { 18 19 if ( 0 === strpos( $class, 'phpDocumentor' ) ) { 20 $file = dirname( DIR_TESTDATA ) . '/includes/' . str_replace( '\\', '/', $class ) . '.php'; 21 require_once $file; 22 } 23 24 } 25 26 /** 27 * Test a function or method for a given class 28 * 29 * @dataProvider dataReflectionTestFunctions 30 * 31 * @param string|array $function The function name, or array of class name and method name. 32 */ 33 public function testFunction( $function ) { 34 35 // We can't pass Reflector objects in here because they get printed out in their 36 // entirety when a test fails 37 38 if ( is_array( $function ) ) { 39 $ref = new ReflectionMethod( $function[0], $function[1] ); 40 $name = $function[0] . '::' . $function[1] . '()'; 41 } else { 42 $ref = new ReflectionFunction( $function ); 43 $name = $function . '()'; 44 } 45 46 $docblock = new \phpDocumentor\Reflection\DocBlock( $ref ); 47 $doc_comment = $ref->getDocComment(); 48 $method_params = $ref->getParameters(); 49 $doc_params = $docblock->getTagsByName( 'param' ); 50 51 $this->assertNotFalse( $doc_comment, sprintf( 52 'The docblock for `%s` should not be missing.', 53 $name 54 ) ); 55 56 $this->assertNotEmpty( $docblock->getShortDescription(), sprintf( 57 'The docblock description for `%s` should not be empty.', 58 $name 59 ) ); 60 61 $this->assertSame( count( $method_params ), count( $doc_params ), sprintf( 62 'The number of @param docs for `%s` should match its number of parameters.', 63 $name 64 ) ); 65 66 foreach ( $method_params as $i => $param ) { 67 68 $param_doc = $doc_params[ $i ]; 69 $description = $param_doc->getDescription(); 70 $content = $param_doc->getContent(); 71 72 $is_hash = ( ( 0 === strpos( $description, '{' ) ) && ( ( strlen( $description ) - 1 ) === strrpos( $description, '}' ) ) ); 73 74 if ( $is_hash ) { 75 $lines = explode( "\n", $description ); 76 $description = $lines[1]; 77 } 78 79 $this->assertNotEmpty( $description, sprintf( 80 'The @param description for the `%s` parameter of `%s` should not be empty.', 81 $param_doc->getVariableName(), 82 $name 83 ) ); 84 85 list( $param_doc_type, $param_doc_name ) = preg_split( '#\s+#', $param_doc->getContent() ); 86 87 $this->assertSame( '$' . $param->getName(), $param_doc_name, sprintf( 88 'The @param name for the `%s` parameter of `%s` is incorrect.', 89 '$' . $param->getName(), 90 $name 91 ) ); 92 93 if ( $param->isArray() ) { 94 $this->assertNotFalse( strpos( $param_doc_type, 'array' ), sprintf( 95 'The @param type hint for the `%s` parameter of `%s` should state that it accepts an array.', 96 $param_doc->getVariableName(), 97 $name 98 ) ); 99 } 100 101 if ( ( $param_class = $param->getClass() ) && ( 'stdClass' !== $param_class->getName() ) ) { 102 $this->assertNotFalse( strpos( $param_doc_type, $param_class->getName() ), sprintf( 103 'The @param type hint for the `%s` parameter of `%s` should state that it accepts an object of type `%s`.', 104 $param_doc->getVariableName(), 105 $name, 106 $param_class->getName() 107 ) ); 108 } 109 110 $this->assertFalse( strpos( $param_doc_type, 'callback' ), sprintf( 111 '`callback` is not a valid type. `callable` should be used in the @param type hint for the `%s` parameter of `%s` instead.', 112 $param_doc->getVariableName(), 113 $name 114 ) ); 115 116 if ( $param->isCallable() ) { 117 $this->assertNotFalse( strpos( $param_doc_type, 'callable' ), sprintf( 118 'The @param type hint for the `%s` parameter of `%s` should state that it accepts a callable.', 119 $param_doc->getVariableName(), 120 $name 121 ) ); 122 } 123 124 if ( $param->isOptional() ) { 125 $this->assertNotFalse( strpos( $description, 'Optional' ), sprintf( 126 'The @param description for the optional `%s` parameter of `%s` should state that it is optional.', 127 $param_doc->getVariableName(), 128 $name 129 ) ); 130 } else { 131 $this->assertFalse( strpos( $description, 'Optional.' ), sprintf( 132 'The @param description for the required `%s` parameter of `%s` should not state that it is optional.', 133 $param_doc->getVariableName(), 134 $name 135 ) ); 136 } 137 138 if ( $param->isDefaultValueAvailable() ) { 139 $this->assertNotFalse( strpos( $description, 'Default ' ), sprintf( 140 'The @param description for the `%s` parameter of `%s` should state its default value.', 141 $param_doc->getVariableName(), 142 $name 143 ) ); 144 } else { 145 // print_r($param->getDefaultValue()); 146 $this->assertFalse( strpos( $description, 'Default ' ), sprintf( 147 'The @param description for the `%s` parameter of `%s` should not state a default value.', 148 $param_doc->getVariableName(), 149 $name 150 ) ); 151 } 152 153 } 154 155 } 156 157 protected static function rsearch( $folder, $ext ) { 158 $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $folder ) ); 159 160 $files = array(); 161 162 foreach ( $iterator as $file ) { 163 164 if ( $file->isDir() ) { 165 continue; 166 } 167 if ( $ext !== $file->getExtension() ) { 168 continue; 169 } 170 171 $files[] = $file->getPathname(); 172 173 } 174 return $files; 175 } 176 177 public function dataReflectionTestFunctions() { 178 179 $to_search = ABSPATH . 'wp-includes/rest-api'; 180 181 // Recursive: 182 // $files = self::rsearch( $to_search, 'php' ); 183 184 // Non-recursive 185 $files = glob( $to_search . '/*.php' ); 186 187 $data = array(); 188 189 $test_functions = false; 190 $test_classes = true; 191 192 foreach ( $files as $file ) { 193 194 if ( $test_functions ) { 195 196 preg_match_all( '#^function (\w+)#m', file_get_contents( $file ), $matches ); 197 198 if ( ! empty( $matches ) && ! empty( $matches[1] ) ) { 199 foreach ( $matches[1] as $function ) { 200 if ( ! function_exists($function)) { 201 continue; 202 } 203 $data[] = array( 204 $function 205 ); 206 } 207 } 208 209 } 210 211 if ( $test_classes ) { 212 213 preg_match_all( '#^class (\w+)#m', file_get_contents( $file ), $matches ); 214 215 if ( ! empty( $matches ) && ! empty( $matches[1] ) ) { 216 217 foreach ( $matches[1] as $class ) { 218 219 if ( ! class_exists( $class ) ) { 220 continue; 221 } 222 223 $class_ref = new ReflectionClass( $class ); 224 225 foreach ( $class_ref->getMethods() as $method_ref ) { 226 227 $data[] = array( 228 array( 229 $class, 230 $method_ref->getName(), 231 ), 232 ); 233 234 } 235 236 } 237 } 238 239 } 240 241 } 242 243 return $data; 244 245 } 246 247 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Context.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Vasil Rangelov <boen.robot@gmail.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock; 14 15 /** 16 * The context in which a DocBlock occurs. 17 * 18 * @author Vasil Rangelov <boen.robot@gmail.com> 19 * @license http://www.opensource.org/licenses/mit-license.php MIT 20 * @link http://phpdoc.org 21 */ 22 class Context 23 { 24 /** @var string The current namespace. */ 25 protected $namespace = ''; 26 27 /** @var array List of namespace aliases => Fully Qualified Namespace. */ 28 protected $namespace_aliases = array(); 29 30 /** @var string Name of the structural element, within the namespace. */ 31 protected $lsen = ''; 32 33 /** 34 * Cteates a new context. 35 * @param string $namespace The namespace where this DocBlock 36 * resides in. 37 * @param array $namespace_aliases List of namespace aliases => Fully 38 * Qualified Namespace. 39 * @param string $lsen Name of the structural element, within 40 * the namespace. 41 */ 42 public function __construct( 43 $namespace = '', 44 array $namespace_aliases = array(), 45 $lsen = '' 46 ) { 47 if (!empty($namespace)) { 48 $this->setNamespace($namespace); 49 } 50 $this->setNamespaceAliases($namespace_aliases); 51 $this->setLSEN($lsen); 52 } 53 54 /** 55 * @return string The namespace where this DocBlock resides in. 56 */ 57 public function getNamespace() 58 { 59 return $this->namespace; 60 } 61 62 /** 63 * @return array List of namespace aliases => Fully Qualified Namespace. 64 */ 65 public function getNamespaceAliases() 66 { 67 return $this->namespace_aliases; 68 } 69 70 /** 71 * Returns the Local Structural Element Name. 72 * 73 * @return string Name of the structural element, within the namespace. 74 */ 75 public function getLSEN() 76 { 77 return $this->lsen; 78 } 79 80 /** 81 * Sets a new namespace. 82 * 83 * Sets a new namespace for the context. Leading and trailing slashes are 84 * trimmed, and the keywords "global" and "default" are treated as aliases 85 * to no namespace. 86 * 87 * @param string $namespace The new namespace to set. 88 * 89 * @return $this 90 */ 91 public function setNamespace($namespace) 92 { 93 if ('global' !== $namespace 94 && 'default' !== $namespace 95 ) { 96 // Srip leading and trailing slash 97 $this->namespace = trim((string)$namespace, '\\'); 98 } else { 99 $this->namespace = ''; 100 } 101 return $this; 102 } 103 104 /** 105 * Sets the namespace aliases, replacing all previous ones. 106 * 107 * @param array $namespace_aliases List of namespace aliases => Fully 108 * Qualified Namespace. 109 * 110 * @return $this 111 */ 112 public function setNamespaceAliases(array $namespace_aliases) 113 { 114 $this->namespace_aliases = array(); 115 foreach ($namespace_aliases as $alias => $fqnn) { 116 $this->setNamespaceAlias($alias, $fqnn); 117 } 118 return $this; 119 } 120 121 /** 122 * Adds a namespace alias to the context. 123 * 124 * @param string $alias The alias name (the part after "as", or the last 125 * part of the Fully Qualified Namespace Name) to add. 126 * @param string $fqnn The Fully Qualified Namespace Name for this alias. 127 * Any form of leading/trailing slashes are accepted, but what will be 128 * stored is a name, prefixed with a slash, and no trailing slash. 129 * 130 * @return $this 131 */ 132 public function setNamespaceAlias($alias, $fqnn) 133 { 134 $this->namespace_aliases[$alias] = '\\' . trim((string)$fqnn, '\\'); 135 return $this; 136 } 137 138 /** 139 * Sets a new Local Structural Element Name. 140 * 141 * Sets a new Local Structural Element Name. A local name also contains 142 * punctuation determining the kind of structural element (e.g. trailing "(" 143 * and ")" for functions and methods). 144 * 145 * @param string $lsen The new local name of a structural element. 146 * 147 * @return $this 148 */ 149 public function setLSEN($lsen) 150 { 151 $this->lsen = (string)$lsen; 152 return $this; 153 } 154 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Description.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock; 14 15 use phpDocumentor\Reflection\DocBlock; 16 17 /** 18 * Parses a Description of a DocBlock or tag. 19 * 20 * @author Mike van Riel <mike.vanriel@naenius.com> 21 * @license http://www.opensource.org/licenses/mit-license.php MIT 22 * @link http://phpdoc.org 23 */ 24 class Description implements \Reflector 25 { 26 /** @var string */ 27 protected $contents = ''; 28 29 /** @var array The contents, as an array of strings and Tag objects. */ 30 protected $parsedContents = null; 31 32 /** @var DocBlock The DocBlock which this description belongs to. */ 33 protected $docblock = null; 34 35 /** 36 * Populates the fields of a description. 37 * 38 * @param string $content The description's conetnts. 39 * @param DocBlock $docblock The DocBlock which this description belongs to. 40 */ 41 public function __construct($content, DocBlock $docblock = null) 42 { 43 $this->setContent($content)->setDocBlock($docblock); 44 } 45 46 /** 47 * Gets the text of this description. 48 * 49 * @return string 50 */ 51 public function getContents() 52 { 53 return $this->contents; 54 } 55 56 /** 57 * Sets the text of this description. 58 * 59 * @param string $content The new text of this description. 60 * 61 * @return $this 62 */ 63 public function setContent($content) 64 { 65 $this->contents = trim($content); 66 67 $this->parsedContents = null; 68 return $this; 69 } 70 71 /** 72 * Returns the parsed text of this description. 73 * 74 * @return array An array of strings and tag objects, in the order they 75 * occur within the description. 76 */ 77 public function getParsedContents() 78 { 79 if (null === $this->parsedContents) { 80 $this->parsedContents = preg_split( 81 '/\{ 82 # "{@}" is not a valid inline tag. This ensures that 83 # we do not treat it as one, but treat it literally. 84 (?!@\}) 85 # We want to capture the whole tag line, but without the 86 # inline tag delimiters. 87 (\@ 88 # Match everything up to the next delimiter. 89 [^{}]* 90 # Nested inline tag content should not be captured, or 91 # it will appear in the result separately. 92 (?: 93 # Match nested inline tags. 94 (?: 95 # Because we did not catch the tag delimiters 96 # earlier, we must be explicit with them here. 97 # Notice that this also matches "{}", as a way 98 # to later introduce it as an escape sequence. 99 \{(?1)?\} 100 | 101 # Make sure we match hanging "{". 102 \{ 103 ) 104 # Match content after the nested inline tag. 105 [^{}]* 106 )* # If there are more inline tags, match them as well. 107 # We use "*" since there may not be any nested inline 108 # tags. 109 ) 110 \}/Sux', 111 $this->contents, 112 null, 113 PREG_SPLIT_DELIM_CAPTURE 114 ); 115 116 $count = count($this->parsedContents); 117 for ($i=1; $i<$count; $i += 2) { 118 $this->parsedContents[$i] = Tag::createInstance( 119 $this->parsedContents[$i], 120 $this->docblock 121 ); 122 } 123 124 //In order to allow "literal" inline tags, the otherwise invalid 125 //sequence "{@}" is changed to "@", and "{}" is changed to "}". 126 //See unit tests for examples. 127 for ($i=0; $i<$count; $i += 2) { 128 $this->parsedContents[$i] = str_replace( 129 array('{@}', '{}'), 130 array('@', '}'), 131 $this->parsedContents[$i] 132 ); 133 } 134 } 135 return $this->parsedContents; 136 } 137 138 /** 139 * Return a formatted variant of the Long Description using MarkDown. 140 * 141 * @todo this should become a more intelligent piece of code where the 142 * configuration contains a setting what format long descriptions are. 143 * 144 * @codeCoverageIgnore Will be removed soon, in favor of adapters at 145 * PhpDocumentor itself that will process text in various formats. 146 * 147 * @return string 148 */ 149 public function getFormattedContents() 150 { 151 $result = $this->contents; 152 153 // if the long description contains a plain HTML <code> element, surround 154 // it with a pre element. Please note that we explicitly used str_replace 155 // and not preg_replace to gain performance 156 if (strpos($result, '<code>') !== false) { 157 $result = str_replace( 158 array('<code>', "<code>\r\n", "<code>\n", "<code>\r", '</code>'), 159 array('<pre><code>', '<code>', '<code>', '<code>', '</code></pre>'), 160 $result 161 ); 162 } 163 164 if (class_exists('Parsedown')) { 165 $markdown = \Parsedown::instance(); 166 $result = $markdown->parse($result); 167 } elseif (class_exists('dflydev\markdown\MarkdownExtraParser')) { 168 $markdown = new \dflydev\markdown\MarkdownExtraParser(); 169 $result = $markdown->transformMarkdown($result); 170 } 171 172 return trim($result); 173 } 174 175 /** 176 * Gets the docblock this tag belongs to. 177 * 178 * @return DocBlock The docblock this description belongs to. 179 */ 180 public function getDocBlock() 181 { 182 return $this->docblock; 183 } 184 185 /** 186 * Sets the docblock this tag belongs to. 187 * 188 * @param DocBlock $docblock The new docblock this description belongs to. 189 * Setting NULL removes any association. 190 * 191 * @return $this 192 */ 193 public function setDocBlock(DocBlock $docblock = null) 194 { 195 $this->docblock = $docblock; 196 197 return $this; 198 } 199 200 /** 201 * Builds a string representation of this object. 202 * 203 * @todo determine the exact format as used by PHP Reflection 204 * and implement it. 205 * 206 * @return void 207 * @codeCoverageIgnore Not yet implemented 208 */ 209 public static function export() 210 { 211 throw new \Exception('Not yet implemented'); 212 } 213 214 /** 215 * Returns the long description as a string. 216 * 217 * @return string 218 */ 219 public function __toString() 220 { 221 return $this->getContents(); 222 } 223 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Location.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Vasil Rangelov <boen.robot@gmail.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock; 14 15 /** 16 * The location a DocBlock occurs within a file. 17 * 18 * @author Vasil Rangelov <boen.robot@gmail.com> 19 * @license http://www.opensource.org/licenses/mit-license.php MIT 20 * @link http://phpdoc.org 21 */ 22 class Location 23 { 24 /** @var int Line where the DocBlock text starts. */ 25 protected $lineNumber = 0; 26 27 /** @var int Column where the DocBlock text starts. */ 28 protected $columnNumber = 0; 29 30 public function __construct( 31 $lineNumber = 0, 32 $columnNumber = 0 33 ) { 34 $this->setLineNumber($lineNumber)->setColumnNumber($columnNumber); 35 } 36 37 /** 38 * @return int Line where the DocBlock text starts. 39 */ 40 public function getLineNumber() 41 { 42 return $this->lineNumber; 43 } 44 45 /** 46 * 47 * @param type $lineNumber 48 * @return $this 49 */ 50 public function setLineNumber($lineNumber) 51 { 52 $this->lineNumber = (int)$lineNumber; 53 54 return $this; 55 } 56 57 /** 58 * @return int Column where the DocBlock text starts. 59 */ 60 public function getColumnNumber() 61 { 62 return $this->columnNumber; 63 } 64 65 /** 66 * 67 * @param int $columnNumber 68 * @return $this 69 */ 70 public function setColumnNumber($columnNumber) 71 { 72 $this->columnNumber = (int)$columnNumber; 73 74 return $this; 75 } 76 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Serializer.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Barry vd. Heuvel <barryvdh@gmail.com> 8 * @copyright 2013 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock; 14 15 use phpDocumentor\Reflection\DocBlock; 16 17 /** 18 * Serializes a DocBlock instance. 19 * 20 * @author Barry vd. Heuvel <barryvdh@gmail.com> 21 * @license http://www.opensource.org/licenses/mit-license.php MIT 22 * @link http://phpdoc.org 23 */ 24 class Serializer 25 { 26 27 /** @var string The string to indent the comment with. */ 28 protected $indentString = ' '; 29 30 /** @var int The number of times the indent string is repeated. */ 31 protected $indent = 0; 32 33 /** @var bool Whether to indent the first line. */ 34 protected $isFirstLineIndented = true; 35 36 /** @var int|null The max length of a line. */ 37 protected $lineLength = null; 38 39 /** 40 * Create a Serializer instance. 41 * 42 * @param int $indent The number of times the indent string is 43 * repeated. 44 * @param string $indentString The string to indent the comment with. 45 * @param bool $indentFirstLine Whether to indent the first line. 46 * @param int|null $lineLength The max length of a line or NULL to 47 * disable line wrapping. 48 */ 49 public function __construct( 50 $indent = 0, 51 $indentString = ' ', 52 $indentFirstLine = true, 53 $lineLength = null 54 ) { 55 $this->setIndentationString($indentString); 56 $this->setIndent($indent); 57 $this->setIsFirstLineIndented($indentFirstLine); 58 $this->setLineLength($lineLength); 59 } 60 61 /** 62 * Sets the string to indent comments with. 63 * 64 * @param string $indentationString The string to indent comments with. 65 * 66 * @return $this This serializer object. 67 */ 68 public function setIndentationString($indentString) 69 { 70 $this->indentString = (string)$indentString; 71 return $this; 72 } 73 74 /** 75 * Gets the string to indent comments with. 76 * 77 * @return string The indent string. 78 */ 79 public function getIndentationString() 80 { 81 return $this->indentString; 82 } 83 84 /** 85 * Sets the number of indents. 86 * 87 * @param int $indent The number of times the indent string is repeated. 88 * 89 * @return $this This serializer object. 90 */ 91 public function setIndent($indent) 92 { 93 $this->indent = (int)$indent; 94 return $this; 95 } 96 97 /** 98 * Gets the number of indents. 99 * 100 * @return int The number of times the indent string is repeated. 101 */ 102 public function getIndent() 103 { 104 return $this->indent; 105 } 106 107 /** 108 * Sets whether or not the first line should be indented. 109 * 110 * Sets whether or not the first line (the one with the "/**") should be 111 * indented. 112 * 113 * @param bool $indentFirstLine The new value for this setting. 114 * 115 * @return $this This serializer object. 116 */ 117 public function setIsFirstLineIndented($indentFirstLine) 118 { 119 $this->isFirstLineIndented = (bool)$indentFirstLine; 120 return $this; 121 } 122 123 /** 124 * Gets whether or not the first line should be indented. 125 * 126 * @return bool Whether or not the first line should be indented. 127 */ 128 public function isFirstLineIndented() 129 { 130 return $this->isFirstLineIndented; 131 } 132 133 /** 134 * Sets the line length. 135 * 136 * Sets the length of each line in the serialization. Content will be 137 * wrapped within this limit. 138 * 139 * @param int|null $lineLength The length of each line. NULL to disable line 140 * wrapping altogether. 141 * 142 * @return $this This serializer object. 143 */ 144 public function setLineLength($lineLength) 145 { 146 $this->lineLength = null === $lineLength ? null : (int)$lineLength; 147 return $this; 148 } 149 150 /** 151 * Gets the line length. 152 * 153 * @return int|null The length of each line or NULL if line wrapping is 154 * disabled. 155 */ 156 public function getLineLength() 157 { 158 return $this->lineLength; 159 } 160 161 /** 162 * Generate a DocBlock comment. 163 * 164 * @param DocBlock The DocBlock to serialize. 165 * 166 * @return string The serialized doc block. 167 */ 168 public function getDocComment(DocBlock $docblock) 169 { 170 $indent = str_repeat($this->indentString, $this->indent); 171 $firstIndent = $this->isFirstLineIndented ? $indent : ''; 172 173 $text = $docblock->getText(); 174 if ($this->lineLength) { 175 //3 === strlen(' * ') 176 $wrapLength = $this->lineLength - strlen($indent) - 3; 177 $text = wordwrap($text, $wrapLength); 178 } 179 $text = str_replace("\n", "\n{$indent} * ", $text); 180 181 $comment = "{$firstIndent}/**\n{$indent} * {$text}\n{$indent} *\n"; 182 183 /** @var Tag $tag */ 184 foreach ($docblock->getTags() as $tag) { 185 $tagText = (string) $tag; 186 if ($this->lineLength) { 187 $tagText = wordwrap($tagText, $wrapLength); 188 } 189 $tagText = str_replace("\n", "\n{$indent} * ", $tagText); 190 191 $comment .= "{$indent} * {$tagText}\n"; 192 } 193 194 $comment .= $indent . ' */'; 195 196 return $comment; 197 } 198 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/AuthorTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Vasil Rangelov <boen.robot@gmail.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 use phpDocumentor\Reflection\DocBlock\Tag; 16 17 /** 18 * Reflection class for an @author tag in a Docblock. 19 * 20 * @author Mike van Riel <mike.vanriel@naenius.com> 21 * @license http://www.opensource.org/licenses/mit-license.php MIT 22 * @link http://phpdoc.org 23 */ 24 class AuthorTag extends Tag 25 { 26 /** 27 * PCRE regular expression matching any valid value for the name component. 28 */ 29 const REGEX_AUTHOR_NAME = '[^\<]*'; 30 31 /** 32 * PCRE regular expression matching any valid value for the email component. 33 */ 34 const REGEX_AUTHOR_EMAIL = '[^\>]*'; 35 36 /** @var string The name of the author */ 37 protected $authorName = ''; 38 39 /** @var string The email of the author */ 40 protected $authorEmail = ''; 41 42 public function getContent() 43 { 44 if (null === $this->content) { 45 $this->content = $this->authorName; 46 if ('' != $this->authorEmail) { 47 $this->content .= "<{$this->authorEmail}>"; 48 } 49 } 50 51 return $this->content; 52 } 53 54 /** 55 * {@inheritdoc} 56 */ 57 public function setContent($content) 58 { 59 parent::setContent($content); 60 if (preg_match( 61 '/^(' . self::REGEX_AUTHOR_NAME . 62 ')(\<(' . self::REGEX_AUTHOR_EMAIL . 63 ')\>)?$/u', 64 $this->description, 65 $matches 66 )) { 67 $this->authorName = trim($matches[1]); 68 if (isset($matches[3])) { 69 $this->authorEmail = trim($matches[3]); 70 } 71 } 72 73 return $this; 74 } 75 76 /** 77 * Gets the author's name. 78 * 79 * @return string The author's name. 80 */ 81 public function getAuthorName() 82 { 83 return $this->authorName; 84 } 85 86 /** 87 * Sets the author's name. 88 * 89 * @param string $authorName The new author name. 90 * An invalid value will set an empty string. 91 * 92 * @return $this 93 */ 94 public function setAuthorName($authorName) 95 { 96 $this->content = null; 97 $this->authorName 98 = preg_match('/^' . self::REGEX_AUTHOR_NAME . '$/u', $authorName) 99 ? $authorName : ''; 100 101 return $this; 102 } 103 104 /** 105 * Gets the author's email. 106 * 107 * @return string The author's email. 108 */ 109 public function getAuthorEmail() 110 { 111 return $this->authorEmail; 112 } 113 114 /** 115 * Sets the author's email. 116 * 117 * @param string $authorEmail The new author email. 118 * An invalid value will set an empty string. 119 * 120 * @return $this 121 */ 122 public function setAuthorEmail($authorEmail) 123 { 124 $this->authorEmail 125 = preg_match('/^' . self::REGEX_AUTHOR_EMAIL . '$/u', $authorEmail) 126 ? $authorEmail : ''; 127 128 $this->content = null; 129 return $this; 130 } 131 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/CoversTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 /** 16 * Reflection class for a @covers tag in a Docblock. 17 * 18 * @author Mike van Riel <mike.vanriel@naenius.com> 19 * @license http://www.opensource.org/licenses/mit-license.php MIT 20 * @link http://phpdoc.org 21 */ 22 class CoversTag extends SeeTag 23 { 24 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/DeprecatedTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Vasil Rangelov <boen.robot@gmail.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 use phpDocumentor\Reflection\DocBlock\Tag\VersionTag; 16 17 /** 18 * Reflection class for a @deprecated tag in a Docblock. 19 * 20 * @author Vasil Rangelov <boen.robot@gmail.com> 21 * @license http://www.opensource.org/licenses/mit-license.php MIT 22 * @link http://phpdoc.org 23 */ 24 class DeprecatedTag extends VersionTag 25 { 26 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/ExampleTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Vasil Rangelov <boen.robot@gmail.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 use phpDocumentor\Reflection\DocBlock\Tag; 16 17 /** 18 * Reflection class for a @example tag in a Docblock. 19 * 20 * @author Vasil Rangelov <boen.robot@gmail.com> 21 * @license http://www.opensource.org/licenses/mit-license.php MIT 22 * @link http://phpdoc.org 23 */ 24 class ExampleTag extends SourceTag 25 { 26 /** 27 * @var string Path to a file to use as an example. 28 * May also be an absolute URI. 29 */ 30 protected $filePath = ''; 31 32 /** 33 * @var bool Whether the file path component represents an URI. 34 * This determines how the file portion appears at {@link getContent()}. 35 */ 36 protected $isURI = false; 37 38 /** 39 * {@inheritdoc} 40 */ 41 public function getContent() 42 { 43 if (null === $this->content) { 44 $filePath = ''; 45 if ($this->isURI) { 46 if (false === strpos($this->filePath, ':')) { 47 $filePath = str_replace( 48 '%2F', 49 '/', 50 rawurlencode($this->filePath) 51 ); 52 } else { 53 $filePath = $this->filePath; 54 } 55 } else { 56 $filePath = '"' . $this->filePath . '"'; 57 } 58 59 $this->content = $filePath . ' ' . parent::getContent(); 60 } 61 62 return $this->content; 63 } 64 /** 65 * {@inheritdoc} 66 */ 67 public function setContent($content) 68 { 69 Tag::setContent($content); 70 if (preg_match( 71 '/^ 72 # File component 73 (?: 74 # File path in quotes 75 \"([^\"]+)\" 76 | 77 # File URI 78 (\S+) 79 ) 80 # Remaining content (parsed by SourceTag) 81 (?:\s+(.*))? 82 $/sux', 83 $this->description, 84 $matches 85 )) { 86 if ('' !== $matches[1]) { 87 $this->setFilePath($matches[1]); 88 } else { 89 $this->setFileURI($matches[2]); 90 } 91 92 if (isset($matches[3])) { 93 parent::setContent($matches[3]); 94 } else { 95 $this->setDescription(''); 96 } 97 $this->content = $content; 98 } 99 100 return $this; 101 } 102 103 /** 104 * Returns the file path. 105 * 106 * @return string Path to a file to use as an example. 107 * May also be an absolute URI. 108 */ 109 public function getFilePath() 110 { 111 return $this->filePath; 112 } 113 114 /** 115 * Sets the file path. 116 * 117 * @param string $filePath The new file path to use for the example. 118 * 119 * @return $this 120 */ 121 public function setFilePath($filePath) 122 { 123 $this->isURI = false; 124 $this->filePath = trim($filePath); 125 126 $this->content = null; 127 return $this; 128 } 129 130 /** 131 * Sets the file path as an URI. 132 * 133 * This function is equivalent to {@link setFilePath()}, except that it 134 * convers an URI to a file path before that. 135 * 136 * There is no getFileURI(), as {@link getFilePath()} is compatible. 137 * 138 * @param type $uri The new file URI to use as an example. 139 */ 140 public function setFileURI($uri) 141 { 142 $this->isURI = true; 143 if (false === strpos($uri, ':')) { 144 //Relative URL 145 $this->filePath = rawurldecode( 146 str_replace(array('/', '\\'), '%2F', $uri) 147 ); 148 } else { 149 //Absolute URL or URI. 150 $this->filePath = $uri; 151 } 152 153 $this->content = null; 154 return $this; 155 } 156 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/LinkTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Ben Selby <benmatselby@gmail.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 use phpDocumentor\Reflection\DocBlock\Tag; 16 17 /** 18 * Reflection class for a @link tag in a Docblock. 19 * 20 * @author Ben Selby <benmatselby@gmail.com> 21 * @license http://www.opensource.org/licenses/mit-license.php MIT 22 * @link http://phpdoc.org 23 */ 24 class LinkTag extends Tag 25 { 26 /** @var string */ 27 protected $link = ''; 28 29 /** 30 * {@inheritdoc} 31 */ 32 public function getContent() 33 { 34 if (null === $this->content) { 35 $this->content = "{$this->link} {$this->description}"; 36 } 37 38 return $this->content; 39 } 40 41 /** 42 * {@inheritdoc} 43 */ 44 public function setContent($content) 45 { 46 parent::setContent($content); 47 $parts = preg_split('/\s+/Su', $this->description, 2); 48 49 $this->link = $parts[0]; 50 51 $this->setDescription(isset($parts[1]) ? $parts[1] : $parts[0]); 52 53 $this->content = $content; 54 return $this; 55 } 56 57 /** 58 * Gets the link 59 * 60 * @return string 61 */ 62 public function getLink() 63 { 64 return $this->link; 65 } 66 67 /** 68 * Sets the link 69 * 70 * @param string $link The link 71 * 72 * @return $this 73 */ 74 public function setLink($link) 75 { 76 $this->link = $link; 77 78 $this->content = null; 79 return $this; 80 } 81 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/MethodTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 use phpDocumentor\Reflection\DocBlock\Tag; 16 17 /** 18 * Reflection class for a @method in a Docblock. 19 * 20 * @author Mike van Riel <mike.vanriel@naenius.com> 21 * @license http://www.opensource.org/licenses/mit-license.php MIT 22 * @link http://phpdoc.org 23 */ 24 class MethodTag extends ReturnTag 25 { 26 27 /** @var string */ 28 protected $method_name = ''; 29 30 /** @var string */ 31 protected $arguments = ''; 32 33 /** @var bool */ 34 protected $isStatic = false; 35 36 /** 37 * {@inheritdoc} 38 */ 39 public function getContent() 40 { 41 if (null === $this->content) { 42 $this->content = ''; 43 if ($this->isStatic) { 44 $this->content .= 'static '; 45 } 46 $this->content .= $this->type . 47 " {$this->method_name}({$this->arguments}) " . 48 $this->description; 49 } 50 51 return $this->content; 52 } 53 54 /** 55 * {@inheritdoc} 56 */ 57 public function setContent($content) 58 { 59 Tag::setContent($content); 60 // 1. none or more whitespace 61 // 2. optionally the keyword "static" followed by whitespace 62 // 3. optionally a word with underscores followed by whitespace : as 63 // type for the return value 64 // 4. then optionally a word with underscores followed by () and 65 // whitespace : as method name as used by phpDocumentor 66 // 5. then a word with underscores, followed by ( and any character 67 // until a ) and whitespace : as method name with signature 68 // 6. any remaining text : as description 69 if (preg_match( 70 '/^ 71 # Static keyword 72 # Declates a static method ONLY if type is also present 73 (?: 74 (static) 75 \s+ 76 )? 77 # Return type 78 (?: 79 ([\w\|_\\\\]+) 80 \s+ 81 )? 82 # Legacy method name (not captured) 83 (?: 84 [\w_]+\(\)\s+ 85 )? 86 # Method name 87 ([\w\|_\\\\]+) 88 # Arguments 89 \(([^\)]*)\) 90 \s* 91 # Description 92 (.*) 93 $/sux', 94 $this->description, 95 $matches 96 )) { 97 list( 98 , 99 $static, 100 $this->type, 101 $this->method_name, 102 $this->arguments, 103 $this->description 104 ) = $matches; 105 if ($static) { 106 if (!$this->type) { 107 $this->type = 'static'; 108 } else { 109 $this->isStatic = true; 110 } 111 } else { 112 if (!$this->type) { 113 $this->type = 'void'; 114 } 115 } 116 $this->parsedDescription = null; 117 } 118 119 return $this; 120 } 121 122 /** 123 * Sets the name of this method. 124 * 125 * @param string $method_name The name of the method. 126 * 127 * @return $this 128 */ 129 public function setMethodName($method_name) 130 { 131 $this->method_name = $method_name; 132 133 $this->content = null; 134 return $this; 135 } 136 137 /** 138 * Retrieves the method name. 139 * 140 * @return string 141 */ 142 public function getMethodName() 143 { 144 return $this->method_name; 145 } 146 147 /** 148 * Sets the arguments for this method. 149 * 150 * @param string $arguments A comma-separated arguments line. 151 * 152 * @return void 153 */ 154 public function setArguments($arguments) 155 { 156 $this->arguments = $arguments; 157 158 $this->content = null; 159 return $this; 160 } 161 162 /** 163 * Returns an array containing each argument as array of type and name. 164 * 165 * Please note that the argument sub-array may only contain 1 element if no 166 * type was specified. 167 * 168 * @return string[] 169 */ 170 public function getArguments() 171 { 172 if (empty($this->arguments)) { 173 return array(); 174 } 175 176 $arguments = explode(',', $this->arguments); 177 foreach ($arguments as $key => $value) { 178 $arguments[$key] = explode(' ', trim($value)); 179 } 180 181 return $arguments; 182 } 183 184 /** 185 * Checks whether the method tag describes a static method or not. 186 * 187 * @return bool TRUE if the method declaration is for a static method, FALSE 188 * otherwise. 189 */ 190 public function isStatic() 191 { 192 return $this->isStatic; 193 } 194 195 /** 196 * Sets a new value for whether the method is static or not. 197 * 198 * @param bool $isStatic The new value to set. 199 * 200 * @return $this 201 */ 202 public function setIsStatic($isStatic) 203 { 204 $this->isStatic = $isStatic; 205 206 $this->content = null; 207 return $this; 208 } 209 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/ParamTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 use phpDocumentor\Reflection\DocBlock\Tag; 16 17 /** 18 * Reflection class for a @param tag in a Docblock. 19 * 20 * @author Mike van Riel <mike.vanriel@naenius.com> 21 * @license http://www.opensource.org/licenses/mit-license.php MIT 22 * @link http://phpdoc.org 23 */ 24 class ParamTag extends ReturnTag 25 { 26 /** @var string */ 27 protected $variableName = ''; 28 29 /** @var bool determines whether this is a variadic argument */ 30 protected $isVariadic = false; 31 32 /** 33 * {@inheritdoc} 34 */ 35 public function getContent() 36 { 37 if (null === $this->content) { 38 $this->content 39 = "{$this->type} {$this->variableName} {$this->description}"; 40 } 41 return $this->content; 42 } 43 /** 44 * {@inheritdoc} 45 */ 46 public function setContent($content) 47 { 48 Tag::setContent($content); 49 $parts = preg_split( 50 '/(\s+)/Su', 51 $this->description, 52 3, 53 PREG_SPLIT_DELIM_CAPTURE 54 ); 55 56 // if the first item that is encountered is not a variable; it is a type 57 if (isset($parts[0]) 58 && (strlen($parts[0]) > 0) 59 && ($parts[0][0] !== '$') 60 ) { 61 $this->type = array_shift($parts); 62 array_shift($parts); 63 } 64 65 // if the next item starts with a $ or ...$ it must be the variable name 66 if (isset($parts[0]) 67 && (strlen($parts[0]) > 0) 68 && ($parts[0][0] == '$' || substr($parts[0], 0, 4) === '...$') 69 ) { 70 $this->variableName = array_shift($parts); 71 array_shift($parts); 72 73 if (substr($this->variableName, 0, 3) === '...') { 74 $this->isVariadic = true; 75 $this->variableName = substr($this->variableName, 3); 76 } 77 } 78 79 $this->setDescription(implode('', $parts)); 80 81 $this->content = $content; 82 return $this; 83 } 84 85 /** 86 * Returns the variable's name. 87 * 88 * @return string 89 */ 90 public function getVariableName() 91 { 92 return $this->variableName; 93 } 94 95 /** 96 * Sets the variable's name. 97 * 98 * @param string $name The new name for this variable. 99 * 100 * @return $this 101 */ 102 public function setVariableName($name) 103 { 104 $this->variableName = $name; 105 106 $this->content = null; 107 return $this; 108 } 109 110 /** 111 * Returns whether this tag is variadic. 112 * 113 * @return boolean 114 */ 115 public function isVariadic() 116 { 117 return $this->isVariadic; 118 } 119 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/PropertyReadTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 /** 16 * Reflection class for a @property-read tag in a Docblock. 17 * 18 * @author Mike van Riel <mike.vanriel@naenius.com> 19 * @license http://www.opensource.org/licenses/mit-license.php MIT 20 * @link http://phpdoc.org 21 */ 22 class PropertyReadTag extends PropertyTag 23 { 24 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/PropertyTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 /** 16 * Reflection class for a @property tag in a Docblock. 17 * 18 * @author Mike van Riel <mike.vanriel@naenius.com> 19 * @license http://www.opensource.org/licenses/mit-license.php MIT 20 * @link http://phpdoc.org 21 */ 22 class PropertyTag extends ParamTag 23 { 24 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/PropertyWriteTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 /** 16 * Reflection class for a @property-write tag in a Docblock. 17 * 18 * @author Mike van Riel <mike.vanriel@naenius.com> 19 * @license http://www.opensource.org/licenses/mit-license.php MIT 20 * @link http://phpdoc.org 21 */ 22 class PropertyWriteTag extends PropertyTag 23 { 24 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/ReturnTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 use phpDocumentor\Reflection\DocBlock\Tag; 16 use phpDocumentor\Reflection\DocBlock\Type\Collection; 17 18 /** 19 * Reflection class for a @return tag in a Docblock. 20 * 21 * @author Mike van Riel <mike.vanriel@naenius.com> 22 * @license http://www.opensource.org/licenses/mit-license.php MIT 23 * @link http://phpdoc.org 24 */ 25 class ReturnTag extends Tag 26 { 27 /** @var string The raw type component. */ 28 protected $type = ''; 29 30 /** @var Collection The parsed type component. */ 31 protected $types = null; 32 33 /** 34 * {@inheritdoc} 35 */ 36 public function getContent() 37 { 38 if (null === $this->content) { 39 $this->content = "{$this->type} {$this->description}"; 40 } 41 42 return $this->content; 43 } 44 45 /** 46 * {@inheritdoc} 47 */ 48 public function setContent($content) 49 { 50 parent::setContent($content); 51 52 $parts = preg_split('/\s+/Su', $this->description, 2); 53 54 // any output is considered a type 55 $this->type = $parts[0]; 56 $this->types = null; 57 58 $this->setDescription(isset($parts[1]) ? $parts[1] : ''); 59 60 $this->content = $content; 61 return $this; 62 } 63 64 /** 65 * Returns the unique types of the variable. 66 * 67 * @return string[] 68 */ 69 public function getTypes() 70 { 71 return $this->getTypesCollection()->getArrayCopy(); 72 } 73 74 /** 75 * Returns the type section of the variable. 76 * 77 * @return string 78 */ 79 public function getType() 80 { 81 return (string) $this->getTypesCollection(); 82 } 83 84 /** 85 * Returns the type collection. 86 * 87 * @return void 88 */ 89 protected function getTypesCollection() 90 { 91 if (null === $this->types) { 92 $this->types = new Collection( 93 array($this->type), 94 $this->docblock ? $this->docblock->getContext() : null 95 ); 96 } 97 return $this->types; 98 } 99 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/SeeTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 use phpDocumentor\Reflection\DocBlock\Tag; 16 17 /** 18 * Reflection class for a @see tag in a Docblock. 19 * 20 * @author Mike van Riel <mike.vanriel@naenius.com> 21 * @license http://www.opensource.org/licenses/mit-license.php MIT 22 * @link http://phpdoc.org 23 */ 24 class SeeTag extends Tag 25 { 26 /** @var string */ 27 protected $refers = null; 28 29 /** 30 * {@inheritdoc} 31 */ 32 public function getContent() 33 { 34 if (null === $this->content) { 35 $this->content = "{$this->refers} {$this->description}"; 36 } 37 return $this->content; 38 } 39 40 /** 41 * {@inheritdoc} 42 */ 43 public function setContent($content) 44 { 45 parent::setContent($content); 46 $parts = preg_split('/\s+/Su', $this->description, 2); 47 48 // any output is considered a type 49 $this->refers = $parts[0]; 50 51 $this->setDescription(isset($parts[1]) ? $parts[1] : ''); 52 53 $this->content = $content; 54 return $this; 55 } 56 57 /** 58 * Gets the structural element this tag refers to. 59 * 60 * @return string 61 */ 62 public function getReference() 63 { 64 return $this->refers; 65 } 66 67 /** 68 * Sets the structural element this tag refers to. 69 * 70 * @param string $refers The new type this tag refers to. 71 * 72 * @return $this 73 */ 74 public function setReference($refers) 75 { 76 $this->refers = $refers; 77 78 $this->content = null; 79 return $this; 80 } 81 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/SinceTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Vasil Rangelov <boen.robot@gmail.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 use phpDocumentor\Reflection\DocBlock\Tag\VersionTag; 16 17 /** 18 * Reflection class for a @since tag in a Docblock. 19 * 20 * @author Vasil Rangelov <boen.robot@gmail.com> 21 * @license http://www.opensource.org/licenses/mit-license.php MIT 22 * @link http://phpdoc.org 23 */ 24 class SinceTag extends VersionTag 25 { 26 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/SourceTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Vasil Rangelov <boen.robot@gmail.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 use phpDocumentor\Reflection\DocBlock\Tag; 16 17 /** 18 * Reflection class for a @source tag in a Docblock. 19 * 20 * @author Vasil Rangelov <boen.robot@gmail.com> 21 * @license http://www.opensource.org/licenses/mit-license.php MIT 22 * @link http://phpdoc.org 23 */ 24 class SourceTag extends Tag 25 { 26 /** 27 * @var int The starting line, relative to the structural element's 28 * location. 29 */ 30 protected $startingLine = 1; 31 32 /** 33 * @var int|null The number of lines, relative to the starting line. NULL 34 * means "to the end". 35 */ 36 protected $lineCount = null; 37 38 /** 39 * {@inheritdoc} 40 */ 41 public function getContent() 42 { 43 if (null === $this->content) { 44 $this->content 45 = "{$this->startingLine} {$this->lineCount} {$this->description}"; 46 } 47 48 return $this->content; 49 } 50 51 /** 52 * {@inheritdoc} 53 */ 54 public function setContent($content) 55 { 56 parent::setContent($content); 57 if (preg_match( 58 '/^ 59 # Starting line 60 ([1-9]\d*) 61 \s* 62 # Number of lines 63 (?: 64 ((?1)) 65 \s+ 66 )? 67 # Description 68 (.*) 69 $/sux', 70 $this->description, 71 $matches 72 )) { 73 $this->startingLine = (int)$matches[1]; 74 if (isset($matches[2]) && '' !== $matches[2]) { 75 $this->lineCount = (int)$matches[2]; 76 } 77 $this->setDescription($matches[3]); 78 $this->content = $content; 79 } 80 81 return $this; 82 } 83 84 /** 85 * Gets the starting line. 86 * 87 * @return int The starting line, relative to the structural element's 88 * location. 89 */ 90 public function getStartingLine() 91 { 92 return $this->startingLine; 93 } 94 95 /** 96 * Sets the starting line. 97 * 98 * @param int $startingLine The new starting line, relative to the 99 * structural element's location. 100 * 101 * @return $this 102 */ 103 public function setStartingLine($startingLine) 104 { 105 $this->startingLine = $startingLine; 106 107 $this->content = null; 108 return $this; 109 } 110 111 /** 112 * Returns the number of lines. 113 * 114 * @return int|null The number of lines, relative to the starting line. NULL 115 * means "to the end". 116 */ 117 public function getLineCount() 118 { 119 return $this->lineCount; 120 } 121 122 /** 123 * Sets the number of lines. 124 * 125 * @param int|null $lineCount The new number of lines, relative to the 126 * starting line. NULL means "to the end". 127 * 128 * @return $this 129 */ 130 public function setLineCount($lineCount) 131 { 132 $this->lineCount = $lineCount; 133 134 $this->content = null; 135 return $this; 136 } 137 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/ThrowsTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 /** 16 * Reflection class for a @throws tag in a Docblock. 17 * 18 * @author Mike van Riel <mike.vanriel@naenius.com> 19 * @license http://www.opensource.org/licenses/mit-license.php MIT 20 * @link http://phpdoc.org 21 */ 22 class ThrowsTag extends ReturnTag 23 { 24 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/UsesTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 /** 16 * Reflection class for a @uses tag in a Docblock. 17 * 18 * @author Mike van Riel <mike.vanriel@naenius.com> 19 * @license http://www.opensource.org/licenses/mit-license.php MIT 20 * @link http://phpdoc.org 21 */ 22 class UsesTag extends SeeTag 23 { 24 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/VarTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 /** 16 * Reflection class for a @var tag in a Docblock. 17 * 18 * @author Mike van Riel <mike.vanriel@naenius.com> 19 * @license http://www.opensource.org/licenses/mit-license.php MIT 20 * @link http://phpdoc.org 21 */ 22 class VarTag extends ParamTag 23 { 24 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag/VersionTag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Vasil Rangelov <boen.robot@gmail.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Tag; 14 15 use phpDocumentor\Reflection\DocBlock\Tag; 16 17 /** 18 * Reflection class for a @version tag in a Docblock. 19 * 20 * @author Vasil Rangelov <boen.robot@gmail.com> 21 * @license http://www.opensource.org/licenses/mit-license.php MIT 22 * @link http://phpdoc.org 23 */ 24 class VersionTag extends Tag 25 { 26 /** 27 * PCRE regular expression matching a version vector. 28 * Assumes the "x" modifier. 29 */ 30 const REGEX_VECTOR = '(?: 31 # Normal release vectors. 32 \d\S* 33 | 34 # VCS version vectors. Per PHPCS, they are expected to 35 # follow the form of the VCS name, followed by ":", followed 36 # by the version vector itself. 37 # By convention, popular VCSes like CVS, SVN and GIT use "$" 38 # around the actual version vector. 39 [^\s\:]+\:\s*\$[^\$]+\$ 40 )'; 41 42 /** @var string The version vector. */ 43 protected $version = ''; 44 45 public function getContent() 46 { 47 if (null === $this->content) { 48 $this->content = "{$this->version} {$this->description}"; 49 } 50 51 return $this->content; 52 } 53 54 /** 55 * {@inheritdoc} 56 */ 57 public function setContent($content) 58 { 59 parent::setContent($content); 60 61 if (preg_match( 62 '/^ 63 # The version vector 64 (' . self::REGEX_VECTOR . ') 65 \s* 66 # The description 67 (.+)? 68 $/sux', 69 $this->description, 70 $matches 71 )) { 72 $this->version = $matches[1]; 73 $this->setDescription(isset($matches[2]) ? $matches[2] : ''); 74 $this->content = $content; 75 } 76 77 return $this; 78 } 79 80 /** 81 * Gets the version section of the tag. 82 * 83 * @return string The version section of the tag. 84 */ 85 public function getVersion() 86 { 87 return $this->version; 88 } 89 90 /** 91 * Sets the version section of the tag. 92 * 93 * @param string $version The new version section of the tag. 94 * An invalid value will set an empty string. 95 * 96 * @return $this 97 */ 98 public function setVersion($version) 99 { 100 $this->version 101 = preg_match('/^' . self::REGEX_VECTOR . '$/ux', $version) 102 ? $version 103 : ''; 104 105 $this->content = null; 106 return $this; 107 } 108 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Tag.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock; 14 15 use phpDocumentor\Reflection\DocBlock; 16 17 /** 18 * Parses a tag definition for a DocBlock. 19 * 20 * @author Mike van Riel <mike.vanriel@naenius.com> 21 * @license http://www.opensource.org/licenses/mit-license.php MIT 22 * @link http://phpdoc.org 23 */ 24 class Tag implements \Reflector 25 { 26 /** 27 * PCRE regular expression matching a tag name. 28 */ 29 const REGEX_TAGNAME = '[\w\-\_\\\\]+'; 30 31 /** @var string Name of the tag */ 32 protected $tag = ''; 33 34 /** 35 * @var string|null Content of the tag. 36 * When set to NULL, it means it needs to be regenerated. 37 */ 38 protected $content = ''; 39 40 /** @var string Description of the content of this tag */ 41 protected $description = ''; 42 43 /** 44 * @var array|null The description, as an array of strings and Tag objects. 45 * When set to NULL, it means it needs to be regenerated. 46 */ 47 protected $parsedDescription = null; 48 49 /** @var Location Location of the tag. */ 50 protected $location = null; 51 52 /** @var DocBlock The DocBlock which this tag belongs to. */ 53 protected $docblock = null; 54 55 /** 56 * @var array An array with a tag as a key, and an FQCN to a class that 57 * handles it as an array value. The class is expected to inherit this 58 * class. 59 */ 60 private static $tagHandlerMappings = array( 61 'author' 62 => '\phpDocumentor\Reflection\DocBlock\Tag\AuthorTag', 63 'covers' 64 => '\phpDocumentor\Reflection\DocBlock\Tag\CoversTag', 65 'deprecated' 66 => '\phpDocumentor\Reflection\DocBlock\Tag\DeprecatedTag', 67 'example' 68 => '\phpDocumentor\Reflection\DocBlock\Tag\ExampleTag', 69 'link' 70 => '\phpDocumentor\Reflection\DocBlock\Tag\LinkTag', 71 'method' 72 => '\phpDocumentor\Reflection\DocBlock\Tag\MethodTag', 73 'param' 74 => '\phpDocumentor\Reflection\DocBlock\Tag\ParamTag', 75 'property-read' 76 => '\phpDocumentor\Reflection\DocBlock\Tag\PropertyReadTag', 77 'property' 78 => '\phpDocumentor\Reflection\DocBlock\Tag\PropertyTag', 79 'property-write' 80 => '\phpDocumentor\Reflection\DocBlock\Tag\PropertyWriteTag', 81 'return' 82 => '\phpDocumentor\Reflection\DocBlock\Tag\ReturnTag', 83 'see' 84 => '\phpDocumentor\Reflection\DocBlock\Tag\SeeTag', 85 'since' 86 => '\phpDocumentor\Reflection\DocBlock\Tag\SinceTag', 87 'source' 88 => '\phpDocumentor\Reflection\DocBlock\Tag\SourceTag', 89 'throw' 90 => '\phpDocumentor\Reflection\DocBlock\Tag\ThrowsTag', 91 'throws' 92 => '\phpDocumentor\Reflection\DocBlock\Tag\ThrowsTag', 93 'uses' 94 => '\phpDocumentor\Reflection\DocBlock\Tag\UsesTag', 95 'var' 96 => '\phpDocumentor\Reflection\DocBlock\Tag\VarTag', 97 'version' 98 => '\phpDocumentor\Reflection\DocBlock\Tag\VersionTag' 99 ); 100 101 /** 102 * Factory method responsible for instantiating the correct sub type. 103 * 104 * @param string $tag_line The text for this tag, including description. 105 * @param DocBlock $docblock The DocBlock which this tag belongs to. 106 * @param Location $location Location of the tag. 107 * 108 * @throws \InvalidArgumentException if an invalid tag line was presented. 109 * 110 * @return static A new tag object. 111 */ 112 final public static function createInstance( 113 $tag_line, 114 DocBlock $docblock = null, 115 Location $location = null 116 ) { 117 if (!preg_match( 118 '/^@(' . self::REGEX_TAGNAME . ')(?:\s*([^\s].*)|$)?/us', 119 $tag_line, 120 $matches 121 )) { 122 throw new \InvalidArgumentException( 123 'Invalid tag_line detected: ' . $tag_line 124 ); 125 } 126 127 $handler = __CLASS__; 128 if (isset(self::$tagHandlerMappings[$matches[1]])) { 129 $handler = self::$tagHandlerMappings[$matches[1]]; 130 } elseif (isset($docblock)) { 131 $tagName = (string)new Type\Collection( 132 array($matches[1]), 133 $docblock->getContext() 134 ); 135 136 if (isset(self::$tagHandlerMappings[$tagName])) { 137 $handler = self::$tagHandlerMappings[$tagName]; 138 } 139 } 140 141 return new $handler( 142 $matches[1], 143 isset($matches[2]) ? $matches[2] : '', 144 $docblock, 145 $location 146 ); 147 } 148 149 /** 150 * Registers a handler for tags. 151 * 152 * Registers a handler for tags. The class specified is autoloaded if it's 153 * not available. It must inherit from this class. 154 * 155 * @param string $tag Name of tag to regiser a handler for. When 156 * registering a namespaced tag, the full name, along with a prefixing 157 * slash MUST be provided. 158 * @param string|null $handler FQCN of handler. Specifing NULL removes the 159 * handler for the specified tag, if any. 160 * 161 * @return bool TRUE on success, FALSE on failure. 162 */ 163 final public static function registerTagHandler($tag, $handler) 164 { 165 $tag = trim((string)$tag); 166 167 if (null === $handler) { 168 unset(self::$tagHandlerMappings[$tag]); 169 return true; 170 } 171 172 if ('' !== $tag 173 && class_exists($handler, true) 174 && is_subclass_of($handler, __CLASS__) 175 && !strpos($tag, '\\') //Accept no slash, and 1st slash at offset 0. 176 ) { 177 self::$tagHandlerMappings[$tag] = $handler; 178 return true; 179 } 180 181 return false; 182 } 183 184 /** 185 * Parses a tag and populates the member variables. 186 * 187 * @param string $name Name of the tag. 188 * @param string $content The contents of the given tag. 189 * @param DocBlock $docblock The DocBlock which this tag belongs to. 190 * @param Location $location Location of the tag. 191 */ 192 public function __construct( 193 $name, 194 $content, 195 DocBlock $docblock = null, 196 Location $location = null 197 ) { 198 $this 199 ->setName($name) 200 ->setContent($content) 201 ->setDocBlock($docblock) 202 ->setLocation($location); 203 } 204 205 /** 206 * Gets the name of this tag. 207 * 208 * @return string The name of this tag. 209 */ 210 public function getName() 211 { 212 return $this->tag; 213 } 214 215 /** 216 * Sets the name of this tag. 217 * 218 * @param string $name The new name of this tag. 219 * 220 * @return $this 221 * @throws \InvalidArgumentException When an invalid tag name is provided. 222 */ 223 public function setName($name) 224 { 225 if (!preg_match('/^' . self::REGEX_TAGNAME . '$/u', $name)) { 226 throw new \InvalidArgumentException( 227 'Invalid tag name supplied: ' . $name 228 ); 229 } 230 231 $this->tag = $name; 232 233 return $this; 234 } 235 236 /** 237 * Gets the content of this tag. 238 * 239 * @return string 240 */ 241 public function getContent() 242 { 243 if (null === $this->content) { 244 $this->content = $this->description; 245 } 246 247 return $this->content; 248 } 249 250 /** 251 * Sets the content of this tag. 252 * 253 * @param string $content The new content of this tag. 254 * 255 * @return $this 256 */ 257 public function setContent($content) 258 { 259 $this->setDescription($content); 260 $this->content = $content; 261 262 return $this; 263 } 264 265 /** 266 * Gets the description component of this tag. 267 * 268 * @return string 269 */ 270 public function getDescription() 271 { 272 return $this->description; 273 } 274 275 /** 276 * Sets the description component of this tag. 277 * 278 * @param string $description The new description component of this tag. 279 * 280 * @return $this 281 */ 282 public function setDescription($description) 283 { 284 $this->content = null; 285 $this->parsedDescription = null; 286 $this->description = trim($description); 287 288 return $this; 289 } 290 291 /** 292 * Gets the parsed text of this description. 293 * 294 * @return array An array of strings and tag objects, in the order they 295 * occur within the description. 296 */ 297 public function getParsedDescription() 298 { 299 if (null === $this->parsedDescription) { 300 $description = new Description($this->description, $this->docblock); 301 $this->parsedDescription = $description->getParsedContents(); 302 } 303 return $this->parsedDescription; 304 } 305 306 /** 307 * Gets the docblock this tag belongs to. 308 * 309 * @return DocBlock The docblock this tag belongs to. 310 */ 311 public function getDocBlock() 312 { 313 return $this->docblock; 314 } 315 316 /** 317 * Sets the docblock this tag belongs to. 318 * 319 * @param DocBlock $docblock The new docblock this tag belongs to. Setting 320 * NULL removes any association. 321 * 322 * @return $this 323 */ 324 public function setDocBlock(DocBlock $docblock = null) 325 { 326 $this->docblock = $docblock; 327 328 return $this; 329 } 330 331 /** 332 * Gets the location of the tag. 333 * 334 * @return Location The tag's location. 335 */ 336 public function getLocation() 337 { 338 return $this->location; 339 } 340 341 /** 342 * Sets the location of the tag. 343 * 344 * @param Location $location The new location of the tag. 345 * 346 * @return $this 347 */ 348 public function setLocation(Location $location = null) 349 { 350 $this->location = $location; 351 352 return $this; 353 } 354 355 /** 356 * Builds a string representation of this object. 357 * 358 * @todo determine the exact format as used by PHP Reflection and implement it. 359 * 360 * @return void 361 * @codeCoverageIgnore Not yet implemented 362 */ 363 public static function export() 364 { 365 throw new \Exception('Not yet implemented'); 366 } 367 368 /** 369 * Returns the tag as a serialized string 370 * 371 * @return string 372 */ 373 public function __toString() 374 { 375 return "@{$this->getName()} {$this->getContent()}"; 376 } 377 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock/Type/Collection.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection\DocBlock\Type; 14 15 use phpDocumentor\Reflection\DocBlock\Context; 16 17 /** 18 * Collection 19 * 20 * @author Mike van Riel <mike.vanriel@naenius.com> 21 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 22 * @license http://www.opensource.org/licenses/mit-license.php MIT 23 * @link http://phpdoc.org 24 */ 25 class Collection extends \ArrayObject 26 { 27 /** @var string Definition of the OR operator for types */ 28 const OPERATOR_OR = '|'; 29 30 /** @var string Definition of the ARRAY operator for types */ 31 const OPERATOR_ARRAY = '[]'; 32 33 /** @var string Definition of the NAMESPACE operator in PHP */ 34 const OPERATOR_NAMESPACE = '\\'; 35 36 /** @var string[] List of recognized keywords */ 37 protected static $keywords = array( 38 'string', 'int', 'integer', 'bool', 'boolean', 'float', 'double', 39 'object', 'mixed', 'array', 'resource', 'void', 'null', 'scalar', 40 'callback', 'callable', 'false', 'true', 'self', '$this', 'static' 41 ); 42 43 /** 44 * Current invoking location. 45 * 46 * This is used to prepend to type with a relative location. 47 * May also be 'default' or 'global', in which case they are ignored. 48 * 49 * @var Context 50 */ 51 protected $context = null; 52 53 /** 54 * Registers the namespace and aliases; uses that to add and expand the 55 * given types. 56 * 57 * @param string[] $types Array containing a list of types to add to this 58 * container. 59 * @param Context $location The current invoking location. 60 */ 61 public function __construct( 62 array $types = array(), 63 Context $context = null 64 ) { 65 $this->context = null === $context ? new Context() : $context; 66 67 foreach ($types as $type) { 68 $this->add($type); 69 } 70 } 71 72 /** 73 * Returns the current invoking location. 74 * 75 * @return Context 76 */ 77 public function getContext() 78 { 79 return $this->context; 80 } 81 82 /** 83 * Adds a new type to the collection and expands it if it contains a 84 * relative namespace. 85 * 86 * If a class in the type contains a relative namespace than this collection 87 * will try to expand that into a FQCN. 88 * 89 * @param string $type A 'Type' as defined in the phpDocumentor 90 * documentation. 91 * 92 * @throws \InvalidArgumentException if a non-string argument is passed. 93 * 94 * @see http://phpdoc.org/docs/latest/for-users/types.html for the 95 * definition of a type. 96 * 97 * @return void 98 */ 99 public function add($type) 100 { 101 if (!is_string($type)) { 102 throw new \InvalidArgumentException( 103 'A type should be represented by a string, received: ' 104 .var_export($type, true) 105 ); 106 } 107 108 // separate the type by the OR operator 109 $type_parts = explode(self::OPERATOR_OR, $type); 110 foreach ($type_parts as $part) { 111 $expanded_type = $this->expand($part); 112 if ($expanded_type) { 113 $this[] = $expanded_type; 114 } 115 } 116 } 117 118 /** 119 * Returns a string representation of the collection. 120 * 121 * @return string The resolved types across the collection, separated with 122 * {@link self::OPERATOR_OR}. 123 */ 124 public function __toString() 125 { 126 return implode(self::OPERATOR_OR, $this->getArrayCopy()); 127 } 128 129 /** 130 * Analyzes the given type and returns the FQCN variant. 131 * 132 * When a type is provided this method checks whether it is not a keyword or 133 * Fully Qualified Class Name. If so it will use the given namespace and 134 * aliases to expand the type to a FQCN representation. 135 * 136 * This method only works as expected if the namespace and aliases are set; 137 * no dynamic reflection is being performed here. 138 * 139 * @param string $type The relative or absolute type. 140 * 141 * @uses getNamespace to determine with what to prefix the type name. 142 * @uses getNamespaceAliases to check whether the first part of the relative 143 * type name should not be replaced with another namespace. 144 * 145 * @return string 146 */ 147 protected function expand($type) 148 { 149 $type = trim($type); 150 if (!$type) { 151 return ''; 152 } 153 154 if ($this->isTypeAnArray($type)) { 155 return $this->expand(substr($type, 0, -2)) . self::OPERATOR_ARRAY; 156 } 157 158 if ($this->isRelativeType($type) && !$this->isTypeAKeyword($type)) { 159 $type_parts = explode(self::OPERATOR_NAMESPACE, $type, 2); 160 161 $namespace_aliases = $this->context->getNamespaceAliases(); 162 // if the first segment is not an alias; prepend namespace name and 163 // return 164 if (!isset($namespace_aliases[$type_parts[0]])) { 165 $namespace = $this->context->getNamespace(); 166 if ('' !== $namespace) { 167 $namespace .= self::OPERATOR_NAMESPACE; 168 } 169 return self::OPERATOR_NAMESPACE . $namespace . $type; 170 } 171 172 $type_parts[0] = $namespace_aliases[$type_parts[0]]; 173 $type = implode(self::OPERATOR_NAMESPACE, $type_parts); 174 } 175 176 return $type; 177 } 178 179 /** 180 * Detects whether the given type represents an array. 181 * 182 * @param string $type A relative or absolute type as defined in the 183 * phpDocumentor documentation. 184 * 185 * @return bool 186 */ 187 protected function isTypeAnArray($type) 188 { 189 return substr($type, -2) === self::OPERATOR_ARRAY; 190 } 191 192 /** 193 * Detects whether the given type represents a PHPDoc keyword. 194 * 195 * @param string $type A relative or absolute type as defined in the 196 * phpDocumentor documentation. 197 * 198 * @return bool 199 */ 200 protected function isTypeAKeyword($type) 201 { 202 return in_array(strtolower($type), static::$keywords, true); 203 } 204 205 /** 206 * Detects whether the given type represents a relative or absolute path. 207 * 208 * This method will detect keywords as being absolute; even though they are 209 * not preceeded by a namespace separator. 210 * 211 * @param string $type A relative or absolute type as defined in the 212 * phpDocumentor documentation. 213 * 214 * @return bool 215 */ 216 protected function isRelativeType($type) 217 { 218 return ($type[0] !== self::OPERATOR_NAMESPACE) 219 || $this->isTypeAKeyword($type); 220 } 221 } -
tests/phpunit/includes/phpDocumentor/Reflection/DocBlock.php
1 <?php 2 /** 3 * phpDocumentor 4 * 5 * PHP Version 5.3 6 * 7 * @author Mike van Riel <mike.vanriel@naenius.com> 8 * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com) 9 * @license http://www.opensource.org/licenses/mit-license.php MIT 10 * @link http://phpdoc.org 11 */ 12 13 namespace phpDocumentor\Reflection; 14 15 use phpDocumentor\Reflection\DocBlock\Tag; 16 use phpDocumentor\Reflection\DocBlock\Context; 17 use phpDocumentor\Reflection\DocBlock\Location; 18 19 /** 20 * Parses the DocBlock for any structure. 21 * 22 * @author Mike van Riel <mike.vanriel@naenius.com> 23 * @license http://www.opensource.org/licenses/mit-license.php MIT 24 * @link http://phpdoc.org 25 */ 26 class DocBlock implements \Reflector 27 { 28 /** @var string The opening line for this docblock. */ 29 protected $short_description = ''; 30 31 /** 32 * @var DocBlock\Description The actual 33 * description for this docblock. 34 */ 35 protected $long_description = null; 36 37 /** 38 * @var Tag[] An array containing all 39 * the tags in this docblock; except inline. 40 */ 41 protected $tags = array(); 42 43 /** @var Context Information about the context of this DocBlock. */ 44 protected $context = null; 45 46 /** @var Location Information about the location of this DocBlock. */ 47 protected $location = null; 48 49 /** @var bool Is this DocBlock (the start of) a template? */ 50 protected $isTemplateStart = false; 51 52 /** @var bool Does this DocBlock signify the end of a DocBlock template? */ 53 protected $isTemplateEnd = false; 54 55 /** 56 * Parses the given docblock and populates the member fields. 57 * 58 * The constructor may also receive namespace information such as the 59 * current namespace and aliases. This information is used by some tags 60 * (e.g. @return, @param, etc.) to turn a relative Type into a FQCN. 61 * 62 * @param \Reflector|string $docblock A docblock comment (including 63 * asterisks) or reflector supporting the getDocComment method. 64 * @param Context $context The context in which the DocBlock 65 * occurs. 66 * @param Location $location The location within the file that this 67 * DocBlock occurs in. 68 * 69 * @throws \InvalidArgumentException if the given argument does not have the 70 * getDocComment method. 71 */ 72 public function __construct( 73 $docblock, 74 Context $context = null, 75 Location $location = null 76 ) { 77 if (is_object($docblock)) { 78 if (!method_exists($docblock, 'getDocComment')) { 79 throw new \InvalidArgumentException( 80 'Invalid object passed; the given reflector must support ' 81 . 'the getDocComment method' 82 ); 83 } 84 85 $docblock = $docblock->getDocComment(); 86 } 87 88 $docblock = $this->cleanInput($docblock); 89 90 list($templateMarker, $short, $long, $tags) = $this->splitDocBlock($docblock); 91 $this->isTemplateStart = $templateMarker === '#@+'; 92 $this->isTemplateEnd = $templateMarker === '#@-'; 93 $this->short_description = $short; 94 $this->long_description = new DocBlock\Description($long, $this); 95 $this->parseTags($tags); 96 97 $this->context = $context; 98 $this->location = $location; 99 } 100 101 /** 102 * Strips the asterisks from the DocBlock comment. 103 * 104 * @param string $comment String containing the comment text. 105 * 106 * @return string 107 */ 108 protected function cleanInput($comment) 109 { 110 $comment = trim( 111 preg_replace( 112 '#[ \t]*(?:\/\*\*|\*\/|\*)?[ \t]{0,1}(.*)?#u', 113 '$1', 114 $comment 115 ) 116 ); 117 118 // reg ex above is not able to remove */ from a single line docblock 119 if (substr($comment, -2) == '*/') { 120 $comment = trim(substr($comment, 0, -2)); 121 } 122 123 // normalize strings 124 $comment = str_replace(array("\r\n", "\r"), "\n", $comment); 125 126 return $comment; 127 } 128 129 /** 130 * Splits the DocBlock into a template marker, summary, description and block of tags. 131 * 132 * @param string $comment Comment to split into the sub-parts. 133 * 134 * @author Richard van Velzen (@_richardJ) Special thanks to Richard for the regex responsible for the split. 135 * @author Mike van Riel <me@mikevanriel.com> for extending the regex with template marker support. 136 * 137 * @return string[] containing the template marker (if any), summary, description and a string containing the tags. 138 */ 139 protected function splitDocBlock($comment) 140 { 141 // Performance improvement cheat: if the first character is an @ then only tags are in this DocBlock. This 142 // method does not split tags so we return this verbatim as the fourth result (tags). This saves us the 143 // performance impact of running a regular expression 144 if (strpos($comment, '@') === 0) { 145 return array('', '', '', $comment); 146 } 147 148 // clears all extra horizontal whitespace from the line endings to prevent parsing issues 149 $comment = preg_replace('/\h*$/Sum', '', $comment); 150 151 /* 152 * Splits the docblock into a template marker, short description, long description and tags section 153 * 154 * - The template marker is empty, #@+ or #@- if the DocBlock starts with either of those (a newline may 155 * occur after it and will be stripped). 156 * - The short description is started from the first character until a dot is encountered followed by a 157 * newline OR two consecutive newlines (horizontal whitespace is taken into account to consider spacing 158 * errors). This is optional. 159 * - The long description, any character until a new line is encountered followed by an @ and word 160 * characters (a tag). This is optional. 161 * - Tags; the remaining characters 162 * 163 * Big thanks to RichardJ for contributing this Regular Expression 164 */ 165 preg_match( 166 '/ 167 \A 168 # 1. Extract the template marker 169 (?:(\#\@\+|\#\@\-)\n?)? 170 171 # 2. Extract the summary 172 (?: 173 (?! @\pL ) # The summary may not start with an @ 174 ( 175 [^\n.]+ 176 (?: 177 (?! \. \n | \n{2} ) # End summary upon a dot followed by newline or two newlines 178 [\n.] (?! [ \t]* @\pL ) # End summary when an @ is found as first character on a new line 179 [^\n.]+ # Include anything else 180 )* 181 \.? 182 )? 183 ) 184 185 # 3. Extract the description 186 (?: 187 \s* # Some form of whitespace _must_ precede a description because a summary must be there 188 (?! @\pL ) # The description may not start with an @ 189 ( 190 [^\n]+ 191 (?: \n+ 192 (?! [ \t]* @\pL ) # End description when an @ is found as first character on a new line 193 [^\n]+ # Include anything else 194 )* 195 ) 196 )? 197 198 # 4. Extract the tags (anything that follows) 199 (\s+ [\s\S]*)? # everything that follows 200 /ux', 201 $comment, 202 $matches 203 ); 204 array_shift($matches); 205 206 while (count($matches) < 4) { 207 $matches[] = ''; 208 } 209 210 return $matches; 211 } 212 213 /** 214 * Creates the tag objects. 215 * 216 * @param string $tags Tag block to parse. 217 * 218 * @return void 219 */ 220 protected function parseTags($tags) 221 { 222 $result = array(); 223 $tags = trim($tags); 224 if ('' !== $tags) { 225 if ('@' !== $tags[0]) { 226 throw new \LogicException( 227 'A tag block started with text instead of an actual tag,' 228 . ' this makes the tag block invalid: ' . $tags 229 ); 230 } 231 foreach (explode("\n", $tags) as $tag_line) { 232 if (isset($tag_line[0]) && ($tag_line[0] === '@')) { 233 $result[] = $tag_line; 234 } else { 235 $result[count($result) - 1] .= "\n" . $tag_line; 236 } 237 } 238 239 // create proper Tag objects 240 foreach ($result as $key => $tag_line) { 241 $result[$key] = Tag::createInstance(trim($tag_line), $this); 242 } 243 } 244 245 $this->tags = $result; 246 } 247 248 /** 249 * Gets the text portion of the doc block. 250 * 251 * Gets the text portion (short and long description combined) of the doc 252 * block. 253 * 254 * @return string The text portion of the doc block. 255 */ 256 public function getText() 257 { 258 $short = $this->getShortDescription(); 259 $long = $this->getLongDescription()->getContents(); 260 261 if ($long) { 262 return "{$short}\n\n{$long}"; 263 } else { 264 return $short; 265 } 266 } 267 268 /** 269 * Set the text portion of the doc block. 270 * 271 * Sets the text portion (short and long description combined) of the doc 272 * block. 273 * 274 * @param string $docblock The new text portion of the doc block. 275 * 276 * @return $this This doc block. 277 */ 278 public function setText($comment) 279 { 280 list(,$short, $long) = $this->splitDocBlock($comment); 281 $this->short_description = $short; 282 $this->long_description = new DocBlock\Description($long, $this); 283 return $this; 284 } 285 /** 286 * Returns the opening line or also known as short description. 287 * 288 * @return string 289 */ 290 public function getShortDescription() 291 { 292 return $this->short_description; 293 } 294 295 /** 296 * Returns the full description or also known as long description. 297 * 298 * @return DocBlock\Description 299 */ 300 public function getLongDescription() 301 { 302 return $this->long_description; 303 } 304 305 /** 306 * Returns whether this DocBlock is the start of a Template section. 307 * 308 * A Docblock may serve as template for a series of subsequent DocBlocks. This is indicated by a special marker 309 * (`#@+`) that is appended directly after the opening `/**` of a DocBlock. 310 * 311 * An example of such an opening is: 312 * 313 * ``` 314 * /**#@+ 315 * * My DocBlock 316 * * / 317 * ``` 318 * 319 * The description and tags (not the summary!) are copied onto all subsequent DocBlocks and also applied to all 320 * elements that follow until another DocBlock is found that contains the closing marker (`#@-`). 321 * 322 * @see self::isTemplateEnd() for the check whether a closing marker was provided. 323 * 324 * @return boolean 325 */ 326 public function isTemplateStart() 327 { 328 return $this->isTemplateStart; 329 } 330 331 /** 332 * Returns whether this DocBlock is the end of a Template section. 333 * 334 * @see self::isTemplateStart() for a more complete description of the Docblock Template functionality. 335 * 336 * @return boolean 337 */ 338 public function isTemplateEnd() 339 { 340 return $this->isTemplateEnd; 341 } 342 343 /** 344 * Returns the current context. 345 * 346 * @return Context 347 */ 348 public function getContext() 349 { 350 return $this->context; 351 } 352 353 /** 354 * Returns the current location. 355 * 356 * @return Location 357 */ 358 public function getLocation() 359 { 360 return $this->location; 361 } 362 363 /** 364 * Returns the tags for this DocBlock. 365 * 366 * @return Tag[] 367 */ 368 public function getTags() 369 { 370 return $this->tags; 371 } 372 373 /** 374 * Returns an array of tags matching the given name. If no tags are found 375 * an empty array is returned. 376 * 377 * @param string $name String to search by. 378 * 379 * @return Tag[] 380 */ 381 public function getTagsByName($name) 382 { 383 $result = array(); 384 385 /** @var Tag $tag */ 386 foreach ($this->getTags() as $tag) { 387 if ($tag->getName() != $name) { 388 continue; 389 } 390 391 $result[] = $tag; 392 } 393 394 return $result; 395 } 396 397 /** 398 * Checks if a tag of a certain type is present in this DocBlock. 399 * 400 * @param string $name Tag name to check for. 401 * 402 * @return bool 403 */ 404 public function hasTag($name) 405 { 406 /** @var Tag $tag */ 407 foreach ($this->getTags() as $tag) { 408 if ($tag->getName() == $name) { 409 return true; 410 } 411 } 412 413 return false; 414 } 415 416 /** 417 * Appends a tag at the end of the list of tags. 418 * 419 * @param Tag $tag The tag to add. 420 * 421 * @return Tag The newly added tag. 422 * 423 * @throws \LogicException When the tag belongs to a different DocBlock. 424 */ 425 public function appendTag(Tag $tag) 426 { 427 if (null === $tag->getDocBlock()) { 428 $tag->setDocBlock($this); 429 } 430 431 if ($tag->getDocBlock() === $this) { 432 $this->tags[] = $tag; 433 } else { 434 throw new \LogicException( 435 'This tag belongs to a different DocBlock object.' 436 ); 437 } 438 439 return $tag; 440 } 441 442 443 /** 444 * Builds a string representation of this object. 445 * 446 * @todo determine the exact format as used by PHP Reflection and 447 * implement it. 448 * 449 * @return string 450 * @codeCoverageIgnore Not yet implemented 451 */ 452 public static function export() 453 { 454 throw new \Exception('Not yet implemented'); 455 } 456 457 /** 458 * Returns the exported information (we should use the export static method 459 * BUT this throws an exception at this point). 460 * 461 * @return string 462 * @codeCoverageIgnore Not yet implemented 463 */ 464 public function __toString() 465 { 466 return 'Not yet implemented'; 467 } 468 }