From 6f0fc03c49856a311da30545ac6ba268958171a6 Mon Sep 17 00:00:00 2001 From: Vasil Rangelov Date: Fri, 30 Nov 2012 22:37:41 +0200 Subject: [PATCH] Added setters at Location and Description; Added DocBlock::appendTag(); Minor reorganization at the tag setters; --- src/phpDocumentor/Reflection/DocBlock.php | 41 ++++++++-- .../Reflection/DocBlock/Description.php | 53 +++++++++++-- .../Reflection/DocBlock/Location.php | 39 ++++++++-- .../Reflection/DocBlock/Tag/AuthorTag.php | 26 ++++++- .../Reflection/DocBlock/Tag/ExampleTag.php | 74 +++++++++++++++---- .../Reflection/DocBlock/Tag/LinkTag.php | 13 ++-- .../Reflection/DocBlock/Tag/MethodTag.php | 9 ++- .../Reflection/DocBlock/Tag/ParamTag.php | 28 +++---- .../Reflection/DocBlock/Tag/ReturnTag.php | 9 ++- .../Reflection/DocBlock/Tag/SeeTag.php | 10 +-- .../Reflection/DocBlock/Tag/SourceTag.php | 7 +- .../Reflection/DocBlock/Tag/VersionTag.php | 8 +- 12 files changed, 236 insertions(+), 81 deletions(-) diff --git a/src/phpDocumentor/Reflection/DocBlock.php b/src/phpDocumentor/Reflection/DocBlock.php index b0e04e2..bf36345 100644 --- a/src/phpDocumentor/Reflection/DocBlock.php +++ b/src/phpDocumentor/Reflection/DocBlock.php @@ -12,6 +12,7 @@ namespace phpDocumentor\Reflection; +use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Context; use phpDocumentor\Reflection\DocBlock\Location; @@ -28,13 +29,13 @@ class DocBlock implements \Reflector protected $short_description = ''; /** - * @var \phpDocumentor\Reflection\DocBlock\LongDescription The actual + * @var DocBlock\Description The actual * description for this docblock. */ protected $long_description = null; /** - * @var \phpDocumentor\Reflection\DocBlock\Tags[] An array containing all + * @var Tag[] An array containing all * the tags in this docblock; except inline. */ protected $tags = array(); @@ -221,7 +222,7 @@ class DocBlock implements \Reflector // create proper Tag objects foreach ($result as $key => $tag_line) { - $result[$key] = DocBlock\Tag::createInstance($tag_line, $this); + $result[$key] = Tag::createInstance($tag_line, $this); } } @@ -271,7 +272,7 @@ class DocBlock implements \Reflector /** * Returns the tags for this DocBlock. * - * @return DocBlock\Tag[] + * @return Tag[] */ public function getTags() { @@ -284,13 +285,13 @@ class DocBlock implements \Reflector * * @param string $name String to search by. * - * @return DocBlock\Tag[] + * @return Tag[] */ public function getTagsByName($name) { $result = array(); - /** @var DocBlock\Tag $tag */ + /** @var Tag $tag */ foreach ($this->getTags() as $tag) { if ($tag->getName() != $name) { continue; @@ -311,7 +312,7 @@ class DocBlock implements \Reflector */ public function hasTag($name) { - /** @var DocBlock\Tag $tag */ + /** @var Tag $tag */ foreach ($this->getTags() as $tag) { if ($tag->getName() == $name) { return true; @@ -320,6 +321,32 @@ class DocBlock implements \Reflector return false; } + + /** + * Appends a tag at the end of the list of tags. + * + * @param Tag $tag The tag to add. + * + * @return Tag The newly added tag. + * + * @throws \LogicException When the tag belongs to a different DocBlock. + */ + public function appendTag(Tag $tag) + { + if (null === $tag->getDocBlock()) { + $tag->setDocBlock($this); + } + + if ($tag->getDocBlock() === $this) { + $this->tags[] = $tag; + } else { + throw new \LogicException( + 'This tag belongs to a different DocBlock object.' + ); + } + + return $tag; + } /** * Builds a string representation of this object. diff --git a/src/phpDocumentor/Reflection/DocBlock/Description.php b/src/phpDocumentor/Reflection/DocBlock/Description.php index 4300f55..cbd6b07 100644 --- a/src/phpDocumentor/Reflection/DocBlock/Description.php +++ b/src/phpDocumentor/Reflection/DocBlock/Description.php @@ -35,17 +35,16 @@ class Description implements \Reflector /** * Populates the fields of a description. * - * @param string $content The DocBlock contents without asterisks. + * @param string $content The description's conetnts. * @param DocBlock $docblock The DocBlock which this description belongs to. */ public function __construct($content, DocBlock $docblock = null) { - $this->contents = trim($content); - $this->docblock = $docblock; + $this->setContent($content)->setDocBlock($docblock); } /** - * Returns the text of this description. + * Gets the text of this description. * * @return string */ @@ -54,6 +53,21 @@ class Description implements \Reflector return $this->contents; } + /** + * Sets the text of this description. + * + * @param string $content The new text of this description. + * + * @return $this + */ + public function setContent($content) + { + $this->contents = trim($content); + + $this->parsedContents = null; + return $this; + } + /** * Returns the parsed text of this description. * @@ -98,7 +112,9 @@ class Description implements \Reflector null, PREG_SPLIT_DELIM_CAPTURE ); - for ($i=1, $l = count($this->parsedContents); $i<$l; $i += 2) { + + $count = count($this->parsedContents); + for ($i=1; $i<$count; $i += 2) { $this->parsedContents[$i] = Tag::createInstance( $this->parsedContents[$i], $this->docblock @@ -108,7 +124,7 @@ class Description implements \Reflector //In order to allow "literal" inline tags, the otherwise invalid //sequence "{@}" is changed to "@", and "{}" is changed to "}". //See unit tests for examples. - for ($i=0, $l = count($this->parsedContents); $i<$l; $i += 2) { + for ($i=0; $i<$count; $i += 2) { $this->parsedContents[$i] = str_replace( array('{@}', '{}'), array('@', '}'), @@ -153,6 +169,31 @@ class Description implements \Reflector return trim($result); } + /** + * Gets the docblock this tag belongs to. + * + * @return DocBlock The docblock this description belongs to. + */ + public function getDocBlock() + { + return $this->docblock; + } + + /** + * Sets the docblock this tag belongs to. + * + * @param DocBlock $docblock The new docblock this description belongs to. + * Setting NULL removes any association. + * + * @return $this + */ + public function setDocBlock(DocBlock $docblock = null) + { + $this->docblock = $docblock; + + return $this; + } + /** * Builds a string representation of this object. * diff --git a/src/phpDocumentor/Reflection/DocBlock/Location.php b/src/phpDocumentor/Reflection/DocBlock/Location.php index 09e5180..966ed44 100644 --- a/src/phpDocumentor/Reflection/DocBlock/Location.php +++ b/src/phpDocumentor/Reflection/DocBlock/Location.php @@ -22,17 +22,16 @@ namespace phpDocumentor\Reflection\DocBlock; class Location { /** @var int Line where the DocBlock text starts. */ - protected $line_number = 0; + protected $lineNumber = 0; /** @var int Column where the DocBlock text starts. */ - protected $column_number = 0; + protected $columnNumber = 0; public function __construct( - $line_number = 0, - $column_number = 0 + $lineNumber = 0, + $columnNumber = 0 ) { - $this->line_number = (int)$line_number; - $this->column_number = (int)$column_number; + $this->setLineNumber($lineNumber)->setColumnNumber($columnNumber); } /** @@ -40,7 +39,19 @@ class Location */ public function getLineNumber() { - return $this->line_number; + return $this->lineNumber; + } + + /** + * + * @param type $lineNumber + * @return $this + */ + public function setLineNumber($lineNumber) + { + $this->lineNumber = (int)$lineNumber; + + return $this; } /** @@ -48,6 +59,18 @@ class Location */ public function getColumnNumber() { - return $this->column_number; + return $this->columnNumber; + } + + /** + * + * @param int $columnNumber + * @return $this + */ + public function setColumnNumber($columnNumber) + { + $this->columnNumber = (int)$columnNumber; + + return $this; } } diff --git a/src/phpDocumentor/Reflection/DocBlock/Tag/AuthorTag.php b/src/phpDocumentor/Reflection/DocBlock/Tag/AuthorTag.php index d5e5f83..bacf52e 100644 --- a/src/phpDocumentor/Reflection/DocBlock/Tag/AuthorTag.php +++ b/src/phpDocumentor/Reflection/DocBlock/Tag/AuthorTag.php @@ -23,6 +23,16 @@ use phpDocumentor\Reflection\DocBlock\Tag; */ class AuthorTag extends Tag { + /** + * PCRE regular expression matching any valid value for the name component. + */ + const REGEX_AUTHOR_NAME = '[^\<]*'; + + /** + * PCRE regular expression matching any valid value for the email component. + */ + const REGEX_AUTHOR_EMAIL = '[^\>]*'; + /** @var string The name of the author */ protected $authorName = ''; @@ -48,7 +58,9 @@ class AuthorTag extends Tag { parent::setContent($content); if (preg_match( - '/^([^\<]*)(\<([^\>]*)\>)?$/u', + '/^(' . self::REGEX_AUTHOR_NAME . + ')(\<(' . self::REGEX_AUTHOR_EMAIL . + ')\>)?$/u', $this->description, $matches )) { @@ -75,13 +87,16 @@ class AuthorTag extends Tag * Sets the author's name. * * @param string $authorName The new author name. + * An invalid value will set an empty string. * * @return $this */ public function setAuthorName($authorName) { $this->content = null; - $this->authorName = $authorName; + $this->authorName + = preg_match('/^' . self::REGEX_AUTHOR_NAME . '$/u', $authorName) + ? $authorName : ''; return $this; } @@ -100,14 +115,17 @@ class AuthorTag extends Tag * Sets the author's email. * * @param string $authorEmail The new author email. + * An invalid value will set an empty string. * * @return $this */ public function setAuthorEmail($authorEmail) { - $this->content = null; - $this->authorEmail = $authorEmail; + $this->authorEmail + = preg_match('/^' . self::REGEX_AUTHOR_EMAIL . '$/u', $authorEmail) + ? $authorEmail : ''; + $this->content = null; return $this; } } diff --git a/src/phpDocumentor/Reflection/DocBlock/Tag/ExampleTag.php b/src/phpDocumentor/Reflection/DocBlock/Tag/ExampleTag.php index 9b53379..9173de4 100644 --- a/src/phpDocumentor/Reflection/DocBlock/Tag/ExampleTag.php +++ b/src/phpDocumentor/Reflection/DocBlock/Tag/ExampleTag.php @@ -12,7 +12,6 @@ namespace phpDocumentor\Reflection\DocBlock\Tag; -use phpDocumentor\Reflection\DocBlock; use phpDocumentor\Reflection\DocBlock\Tag; /** @@ -30,13 +29,34 @@ class ExampleTag extends SourceTag */ protected $filePath = ''; + /** + * @var bool Whether the file path component represents an URI. + * This determines how the file portion appears at {@link getContent()}. + */ + protected $isURI = false; + + /** + * {@inheritdoc} + */ public function getContent() { if (null === $this->content) { - $this->content - = (preg_match('/\s/Su', $this->filePath) - ? '"' . $this->filePath . '"' - : $this->filePath) . ' ' . $this->getContent(); + $filePath = ''; + if ($this->isURI) { + if (false === strpos($this->filePath, ':')) { + $filePath = str_replace( + '%2F', + '/', + rawurlencode($this->filePath) + ); + } else { + $filePath = $this->filePath; + } + } else { + $filePath = '"' . $this->filePath . '"'; + } + + $this->content = $filePath . ' ' . $this->getContent(); } return $this->content; @@ -63,14 +83,18 @@ class ExampleTag extends SourceTag $this->description, $matches )) { - $this->setFilePath('' === $matches[1] ? $matches[2] : $matches[1]); + if ('' !== $matches[1]) { + $this->setFilePath($matches[1]); + } else { + $this->setFileURI($matches[2]); + } if (isset($matches[3])) { parent::setContent($matches[3]); - $this->content = $content; } else { - $this->description = ''; + $this->setDescription(''); } + $this->content = $content; } return $this; @@ -90,25 +114,43 @@ class ExampleTag extends SourceTag /** * Sets the file path. * - * @param string $filePath The new file path or URI to use as an example. + * @param string $filePath The new file path to use for the example. * * @return $this */ public function setFilePath($filePath) { - if (preg_match('/\s/Su', $filePath)) { - //Quoted file path. - $this->filePath = trim($filePath); - } elseif (false === strpos($filePath, ':')) { - //Relative URL or a file path with no spaces in it. + $this->isURI = false; + $this->filePath = trim($filePath); + + $this->content = null; + return $this; + } + + /** + * Sets the file path as an URI. + * + * This function is equivalent to {@link setFilePath()}, except that it + * convers an URI to a file path before that. + * + * There is no getFileURI(), as {@link getFilePath()} is compatible. + * + * @param type $uri The new file URI to use as an example. + */ + public function setFileURI($uri) + { + $this->isURI = true; + if (false === strpos($uri, ':')) { + //Relative URL $this->filePath = rawurldecode( - str_replace(array('/', '\\'), '%2F', $filePath) + str_replace(array('/', '\\'), '%2F', $uri) ); } else { //Absolute URL or URI. - $this->filePath = $filePath; + $this->filePath = $uri; } + $this->content = null; return $this; } } diff --git a/src/phpDocumentor/Reflection/DocBlock/Tag/LinkTag.php b/src/phpDocumentor/Reflection/DocBlock/Tag/LinkTag.php index 7b97273..f79f25d 100644 --- a/src/phpDocumentor/Reflection/DocBlock/Tag/LinkTag.php +++ b/src/phpDocumentor/Reflection/DocBlock/Tag/LinkTag.php @@ -44,12 +44,13 @@ class LinkTag extends Tag public function setContent($content) { parent::setContent($content); - $content = preg_split('/\s+/Su', $this->description, 2); + $parts = preg_split('/\s+/Su', $this->description, 2); - $this->link = $content[0]; + $this->link = $parts[0]; - $this->description = isset($content[1]) ? $content[1] : $content[0]; - + $this->setDescription(isset($parts[1]) ? $parts[1] : $parts[0]); + + $this->content = $content; return $this; } @@ -72,9 +73,9 @@ class LinkTag extends Tag */ public function setLink($link) { - $this->content = null; $this->link = $link; - + + $this->content = null; return $this; } } diff --git a/src/phpDocumentor/Reflection/DocBlock/Tag/MethodTag.php b/src/phpDocumentor/Reflection/DocBlock/Tag/MethodTag.php index e77cdf7..ec46942 100644 --- a/src/phpDocumentor/Reflection/DocBlock/Tag/MethodTag.php +++ b/src/phpDocumentor/Reflection/DocBlock/Tag/MethodTag.php @@ -90,6 +90,7 @@ class MethodTag extends ReturnTag if (!$this->type) { $this->type = 'void'; } + $this->parsedDescription = null; } else { echo date('c') . ' ERR (3): @method contained invalid contents: ' . $this->content . PHP_EOL; @@ -107,9 +108,9 @@ class MethodTag extends ReturnTag */ public function setMethodName($method_name) { - $this->content = null; $this->method_name = $method_name; - + + $this->content = null; return $this; } @@ -132,9 +133,9 @@ class MethodTag extends ReturnTag */ public function setArguments($arguments) { - $this->content = null; $this->arguments = $arguments; - + + $this->content = null; return $this; } diff --git a/src/phpDocumentor/Reflection/DocBlock/Tag/ParamTag.php b/src/phpDocumentor/Reflection/DocBlock/Tag/ParamTag.php index 5edab5f..f544a9b 100644 --- a/src/phpDocumentor/Reflection/DocBlock/Tag/ParamTag.php +++ b/src/phpDocumentor/Reflection/DocBlock/Tag/ParamTag.php @@ -12,7 +12,6 @@ namespace phpDocumentor\Reflection\DocBlock\Tag; -use phpDocumentor\Reflection\DocBlock; use phpDocumentor\Reflection\DocBlock\Tag; /** @@ -46,7 +45,7 @@ class ParamTag extends ReturnTag public function setContent($content) { Tag::setContent($content); - $content = preg_split( + $parts = preg_split( '/(\s+)/Su', $this->description, 3, @@ -54,25 +53,26 @@ class ParamTag extends ReturnTag ); // if the first item that is encountered is not a variable; it is a type - if (isset($content[0]) - && (strlen($content[0]) > 0) - && ($content[0][0] !== '$') + if (isset($parts[0]) + && (strlen($parts[0]) > 0) + && ($parts[0][0] !== '$') ) { - $this->type = array_shift($content); - array_shift($content); + $this->type = array_shift($parts); + array_shift($parts); } // if the next item starts with a $ it must be the variable name - if (isset($content[0]) - && (strlen($content[0]) > 0) - && ($content[0][0] == '$') + if (isset($parts[0]) + && (strlen($parts[0]) > 0) + && ($parts[0][0] == '$') ) { - $this->variableName = array_shift($content); - array_shift($content); + $this->variableName = array_shift($parts); + array_shift($parts); } - $this->description = implode('', $content); + $this->setDescription(implode('', $parts)); + $this->content = $content; return $this; } @@ -95,9 +95,9 @@ class ParamTag extends ReturnTag */ public function setVariableName($name) { - $this->content = null; $this->variableName = $name; + $this->content = null; return $this; } } diff --git a/src/phpDocumentor/Reflection/DocBlock/Tag/ReturnTag.php b/src/phpDocumentor/Reflection/DocBlock/Tag/ReturnTag.php index b850496..60fbd1d 100644 --- a/src/phpDocumentor/Reflection/DocBlock/Tag/ReturnTag.php +++ b/src/phpDocumentor/Reflection/DocBlock/Tag/ReturnTag.php @@ -49,13 +49,14 @@ class ReturnTag extends Tag { parent::setContent($content); - $content = preg_split('/\s+/Su', $this->description, 2); + $parts = preg_split('/\s+/Su', $this->description, 2); // any output is considered a type - $this->type = $content[0]; + $this->type = $parts[0]; - $this->description = isset($content[1]) ? $content[1] : ''; - + $this->setDescription(isset($parts[1]) ? $parts[1] : ''); + + $this->content = $content; return $this; } diff --git a/src/phpDocumentor/Reflection/DocBlock/Tag/SeeTag.php b/src/phpDocumentor/Reflection/DocBlock/Tag/SeeTag.php index 2bf827a..4f5f22c 100644 --- a/src/phpDocumentor/Reflection/DocBlock/Tag/SeeTag.php +++ b/src/phpDocumentor/Reflection/DocBlock/Tag/SeeTag.php @@ -12,7 +12,6 @@ namespace phpDocumentor\Reflection\DocBlock\Tag; -use phpDocumentor\Reflection\DocBlock; use phpDocumentor\Reflection\DocBlock\Tag; /** @@ -44,13 +43,14 @@ class SeeTag extends Tag public function setContent($content) { parent::setContent($content); - $content = preg_split('/\s+/Su', $this->description, 2); + $parts = preg_split('/\s+/Su', $this->description, 2); // any output is considered a type - $this->refers = $content[0]; + $this->refers = $parts[0]; - $this->description = isset($content[1]) ? $content[1] : ''; + $this->setDescription(isset($parts[1]) ? $parts[1] : ''); + $this->content = $content; return $this; } @@ -73,9 +73,9 @@ class SeeTag extends Tag */ public function setReference($refers) { - $this->content = null; $this->refers = $refers; + $this->content = null; return $this; } } diff --git a/src/phpDocumentor/Reflection/DocBlock/Tag/SourceTag.php b/src/phpDocumentor/Reflection/DocBlock/Tag/SourceTag.php index 001a281..3400220 100644 --- a/src/phpDocumentor/Reflection/DocBlock/Tag/SourceTag.php +++ b/src/phpDocumentor/Reflection/DocBlock/Tag/SourceTag.php @@ -74,7 +74,8 @@ class SourceTag extends Tag if (isset($matches[2]) && '' !== $matches[2]) { $this->lineCount = (int)$matches[2]; } - $this->description = $matches[3]; + $this->setDescription($matches[3]); + $this->content = $content; } return $this; @@ -101,9 +102,9 @@ class SourceTag extends Tag */ public function setStartingLine($startingLine) { - $this->content = null; $this->startingLine = $startingLine; + $this->content = null; return $this; } @@ -128,9 +129,9 @@ class SourceTag extends Tag */ public function setLineCount($lineCount) { - $this->content = null; $this->lineCount = $lineCount; + $this->content = null; return $this; } } diff --git a/src/phpDocumentor/Reflection/DocBlock/Tag/VersionTag.php b/src/phpDocumentor/Reflection/DocBlock/Tag/VersionTag.php index 5f739da..260f698 100644 --- a/src/phpDocumentor/Reflection/DocBlock/Tag/VersionTag.php +++ b/src/phpDocumentor/Reflection/DocBlock/Tag/VersionTag.php @@ -12,7 +12,6 @@ namespace phpDocumentor\Reflection\DocBlock\Tag; -use phpDocumentor\Reflection\DocBlock; use phpDocumentor\Reflection\DocBlock\Tag; /** @@ -71,7 +70,8 @@ class VersionTag extends Tag $matches )) { $this->version = $matches[1]; - $this->description = isset($matches[2]) ? $matches[2] : ''; + $this->setDescription(isset($matches[2]) ? $matches[2] : ''); + $this->content = $content; } return $this; @@ -91,18 +91,18 @@ class VersionTag extends Tag * Sets the version section of the tag. * * @param string $version The new version section of the tag. - * Invalid version vectors will set the version to an empty string. + * An invalid value will set an empty string. * * @return $this */ public function setVersion($version) { - $this->content = null; $this->version = preg_match('/^' . self::REGEX_VECTOR . '$/ux', $version) ? $version : ''; + $this->content = null; return $this; } }