Added setters at Location and Description;

Added DocBlock::appendTag();
Minor reorganization at the tag setters;
This commit is contained in:
Vasil Rangelov
2012-11-30 22:37:41 +02:00
parent b09525332f
commit 6f0fc03c49
12 changed files with 236 additions and 81 deletions
+34 -7
View File
@@ -12,6 +12,7 @@
namespace phpDocumentor\Reflection; namespace phpDocumentor\Reflection;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Context; use phpDocumentor\Reflection\DocBlock\Context;
use phpDocumentor\Reflection\DocBlock\Location; use phpDocumentor\Reflection\DocBlock\Location;
@@ -28,13 +29,13 @@ class DocBlock implements \Reflector
protected $short_description = ''; protected $short_description = '';
/** /**
* @var \phpDocumentor\Reflection\DocBlock\LongDescription The actual * @var DocBlock\Description The actual
* description for this docblock. * description for this docblock.
*/ */
protected $long_description = null; 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. * the tags in this docblock; except inline.
*/ */
protected $tags = array(); protected $tags = array();
@@ -221,7 +222,7 @@ class DocBlock implements \Reflector
// create proper Tag objects // create proper Tag objects
foreach ($result as $key => $tag_line) { 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. * Returns the tags for this DocBlock.
* *
* @return DocBlock\Tag[] * @return Tag[]
*/ */
public function getTags() public function getTags()
{ {
@@ -284,13 +285,13 @@ class DocBlock implements \Reflector
* *
* @param string $name String to search by. * @param string $name String to search by.
* *
* @return DocBlock\Tag[] * @return Tag[]
*/ */
public function getTagsByName($name) public function getTagsByName($name)
{ {
$result = array(); $result = array();
/** @var DocBlock\Tag $tag */ /** @var Tag $tag */
foreach ($this->getTags() as $tag) { foreach ($this->getTags() as $tag) {
if ($tag->getName() != $name) { if ($tag->getName() != $name) {
continue; continue;
@@ -311,7 +312,7 @@ class DocBlock implements \Reflector
*/ */
public function hasTag($name) public function hasTag($name)
{ {
/** @var DocBlock\Tag $tag */ /** @var Tag $tag */
foreach ($this->getTags() as $tag) { foreach ($this->getTags() as $tag) {
if ($tag->getName() == $name) { if ($tag->getName() == $name) {
return true; return true;
@@ -320,6 +321,32 @@ class DocBlock implements \Reflector
return false; 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. * Builds a string representation of this object.
@@ -35,17 +35,16 @@ class Description implements \Reflector
/** /**
* Populates the fields of a description. * 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. * @param DocBlock $docblock The DocBlock which this description belongs to.
*/ */
public function __construct($content, DocBlock $docblock = null) public function __construct($content, DocBlock $docblock = null)
{ {
$this->contents = trim($content); $this->setContent($content)->setDocBlock($docblock);
$this->docblock = $docblock;
} }
/** /**
* Returns the text of this description. * Gets the text of this description.
* *
* @return string * @return string
*/ */
@@ -54,6 +53,21 @@ class Description implements \Reflector
return $this->contents; 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. * Returns the parsed text of this description.
* *
@@ -98,7 +112,9 @@ class Description implements \Reflector
null, null,
PREG_SPLIT_DELIM_CAPTURE 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] = Tag::createInstance(
$this->parsedContents[$i], $this->parsedContents[$i],
$this->docblock $this->docblock
@@ -108,7 +124,7 @@ class Description implements \Reflector
//In order to allow "literal" inline tags, the otherwise invalid //In order to allow "literal" inline tags, the otherwise invalid
//sequence "{@}" is changed to "@", and "{}" is changed to "}". //sequence "{@}" is changed to "@", and "{}" is changed to "}".
//See unit tests for examples. //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( $this->parsedContents[$i] = str_replace(
array('{@}', '{}'), array('{@}', '{}'),
array('@', '}'), array('@', '}'),
@@ -153,6 +169,31 @@ class Description implements \Reflector
return trim($result); 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. * Builds a string representation of this object.
* *
@@ -22,17 +22,16 @@ namespace phpDocumentor\Reflection\DocBlock;
class Location class Location
{ {
/** @var int Line where the DocBlock text starts. */ /** @var int Line where the DocBlock text starts. */
protected $line_number = 0; protected $lineNumber = 0;
/** @var int Column where the DocBlock text starts. */ /** @var int Column where the DocBlock text starts. */
protected $column_number = 0; protected $columnNumber = 0;
public function __construct( public function __construct(
$line_number = 0, $lineNumber = 0,
$column_number = 0 $columnNumber = 0
) { ) {
$this->line_number = (int)$line_number; $this->setLineNumber($lineNumber)->setColumnNumber($columnNumber);
$this->column_number = (int)$column_number;
} }
/** /**
@@ -40,7 +39,19 @@ class Location
*/ */
public function getLineNumber() 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() 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;
} }
} }
@@ -23,6 +23,16 @@ use phpDocumentor\Reflection\DocBlock\Tag;
*/ */
class AuthorTag extends 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 */ /** @var string The name of the author */
protected $authorName = ''; protected $authorName = '';
@@ -48,7 +58,9 @@ class AuthorTag extends Tag
{ {
parent::setContent($content); parent::setContent($content);
if (preg_match( if (preg_match(
'/^([^\<]*)(\<([^\>]*)\>)?$/u', '/^(' . self::REGEX_AUTHOR_NAME .
')(\<(' . self::REGEX_AUTHOR_EMAIL .
')\>)?$/u',
$this->description, $this->description,
$matches $matches
)) { )) {
@@ -75,13 +87,16 @@ class AuthorTag extends Tag
* Sets the author's name. * Sets the author's name.
* *
* @param string $authorName The new author name. * @param string $authorName The new author name.
* An invalid value will set an empty string.
* *
* @return $this * @return $this
*/ */
public function setAuthorName($authorName) public function setAuthorName($authorName)
{ {
$this->content = null; $this->content = null;
$this->authorName = $authorName; $this->authorName
= preg_match('/^' . self::REGEX_AUTHOR_NAME . '$/u', $authorName)
? $authorName : '';
return $this; return $this;
} }
@@ -100,14 +115,17 @@ class AuthorTag extends Tag
* Sets the author's email. * Sets the author's email.
* *
* @param string $authorEmail The new author email. * @param string $authorEmail The new author email.
* An invalid value will set an empty string.
* *
* @return $this * @return $this
*/ */
public function setAuthorEmail($authorEmail) public function setAuthorEmail($authorEmail)
{ {
$this->content = null; $this->authorEmail
$this->authorEmail = $authorEmail; = preg_match('/^' . self::REGEX_AUTHOR_EMAIL . '$/u', $authorEmail)
? $authorEmail : '';
$this->content = null;
return $this; return $this;
} }
} }
@@ -12,7 +12,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tag;
/** /**
@@ -30,13 +29,34 @@ class ExampleTag extends SourceTag
*/ */
protected $filePath = ''; 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() public function getContent()
{ {
if (null === $this->content) { if (null === $this->content) {
$this->content $filePath = '';
= (preg_match('/\s/Su', $this->filePath) if ($this->isURI) {
? '"' . $this->filePath . '"' if (false === strpos($this->filePath, ':')) {
: $this->filePath) . ' ' . $this->getContent(); $filePath = str_replace(
'%2F',
'/',
rawurlencode($this->filePath)
);
} else {
$filePath = $this->filePath;
}
} else {
$filePath = '"' . $this->filePath . '"';
}
$this->content = $filePath . ' ' . $this->getContent();
} }
return $this->content; return $this->content;
@@ -63,14 +83,18 @@ class ExampleTag extends SourceTag
$this->description, $this->description,
$matches $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])) { if (isset($matches[3])) {
parent::setContent($matches[3]); parent::setContent($matches[3]);
$this->content = $content;
} else { } else {
$this->description = ''; $this->setDescription('');
} }
$this->content = $content;
} }
return $this; return $this;
@@ -90,25 +114,43 @@ class ExampleTag extends SourceTag
/** /**
* Sets the file path. * 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 * @return $this
*/ */
public function setFilePath($filePath) public function setFilePath($filePath)
{ {
if (preg_match('/\s/Su', $filePath)) { $this->isURI = false;
//Quoted file path. $this->filePath = trim($filePath);
$this->filePath = trim($filePath);
} elseif (false === strpos($filePath, ':')) { $this->content = null;
//Relative URL or a file path with no spaces in it. 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( $this->filePath = rawurldecode(
str_replace(array('/', '\\'), '%2F', $filePath) str_replace(array('/', '\\'), '%2F', $uri)
); );
} else { } else {
//Absolute URL or URI. //Absolute URL or URI.
$this->filePath = $filePath; $this->filePath = $uri;
} }
$this->content = null;
return $this; return $this;
} }
} }
@@ -44,12 +44,13 @@ class LinkTag extends Tag
public function setContent($content) public function setContent($content)
{ {
parent::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; return $this;
} }
@@ -72,9 +73,9 @@ class LinkTag extends Tag
*/ */
public function setLink($link) public function setLink($link)
{ {
$this->content = null;
$this->link = $link; $this->link = $link;
$this->content = null;
return $this; return $this;
} }
} }
@@ -90,6 +90,7 @@ class MethodTag extends ReturnTag
if (!$this->type) { if (!$this->type) {
$this->type = 'void'; $this->type = 'void';
} }
$this->parsedDescription = null;
} else { } else {
echo date('c') . ' ERR (3): @method contained invalid contents: ' echo date('c') . ' ERR (3): @method contained invalid contents: '
. $this->content . PHP_EOL; . $this->content . PHP_EOL;
@@ -107,9 +108,9 @@ class MethodTag extends ReturnTag
*/ */
public function setMethodName($method_name) public function setMethodName($method_name)
{ {
$this->content = null;
$this->method_name = $method_name; $this->method_name = $method_name;
$this->content = null;
return $this; return $this;
} }
@@ -132,9 +133,9 @@ class MethodTag extends ReturnTag
*/ */
public function setArguments($arguments) public function setArguments($arguments)
{ {
$this->content = null;
$this->arguments = $arguments; $this->arguments = $arguments;
$this->content = null;
return $this; return $this;
} }
@@ -12,7 +12,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tag;
/** /**
@@ -46,7 +45,7 @@ class ParamTag extends ReturnTag
public function setContent($content) public function setContent($content)
{ {
Tag::setContent($content); Tag::setContent($content);
$content = preg_split( $parts = preg_split(
'/(\s+)/Su', '/(\s+)/Su',
$this->description, $this->description,
3, 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 the first item that is encountered is not a variable; it is a type
if (isset($content[0]) if (isset($parts[0])
&& (strlen($content[0]) > 0) && (strlen($parts[0]) > 0)
&& ($content[0][0] !== '$') && ($parts[0][0] !== '$')
) { ) {
$this->type = array_shift($content); $this->type = array_shift($parts);
array_shift($content); array_shift($parts);
} }
// if the next item starts with a $ it must be the variable name // if the next item starts with a $ it must be the variable name
if (isset($content[0]) if (isset($parts[0])
&& (strlen($content[0]) > 0) && (strlen($parts[0]) > 0)
&& ($content[0][0] == '$') && ($parts[0][0] == '$')
) { ) {
$this->variableName = array_shift($content); $this->variableName = array_shift($parts);
array_shift($content); array_shift($parts);
} }
$this->description = implode('', $content); $this->setDescription(implode('', $parts));
$this->content = $content;
return $this; return $this;
} }
@@ -95,9 +95,9 @@ class ParamTag extends ReturnTag
*/ */
public function setVariableName($name) public function setVariableName($name)
{ {
$this->content = null;
$this->variableName = $name; $this->variableName = $name;
$this->content = null;
return $this; return $this;
} }
} }
@@ -49,13 +49,14 @@ class ReturnTag extends Tag
{ {
parent::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 // 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; return $this;
} }
@@ -12,7 +12,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tag;
/** /**
@@ -44,13 +43,14 @@ class SeeTag extends Tag
public function setContent($content) public function setContent($content)
{ {
parent::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 // 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; return $this;
} }
@@ -73,9 +73,9 @@ class SeeTag extends Tag
*/ */
public function setReference($refers) public function setReference($refers)
{ {
$this->content = null;
$this->refers = $refers; $this->refers = $refers;
$this->content = null;
return $this; return $this;
} }
} }
@@ -74,7 +74,8 @@ class SourceTag extends Tag
if (isset($matches[2]) && '' !== $matches[2]) { if (isset($matches[2]) && '' !== $matches[2]) {
$this->lineCount = (int)$matches[2]; $this->lineCount = (int)$matches[2];
} }
$this->description = $matches[3]; $this->setDescription($matches[3]);
$this->content = $content;
} }
return $this; return $this;
@@ -101,9 +102,9 @@ class SourceTag extends Tag
*/ */
public function setStartingLine($startingLine) public function setStartingLine($startingLine)
{ {
$this->content = null;
$this->startingLine = $startingLine; $this->startingLine = $startingLine;
$this->content = null;
return $this; return $this;
} }
@@ -128,9 +129,9 @@ class SourceTag extends Tag
*/ */
public function setLineCount($lineCount) public function setLineCount($lineCount)
{ {
$this->content = null;
$this->lineCount = $lineCount; $this->lineCount = $lineCount;
$this->content = null;
return $this; return $this;
} }
} }
@@ -12,7 +12,6 @@
namespace phpDocumentor\Reflection\DocBlock\Tag; namespace phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag; use phpDocumentor\Reflection\DocBlock\Tag;
/** /**
@@ -71,7 +70,8 @@ class VersionTag extends Tag
$matches $matches
)) { )) {
$this->version = $matches[1]; $this->version = $matches[1];
$this->description = isset($matches[2]) ? $matches[2] : ''; $this->setDescription(isset($matches[2]) ? $matches[2] : '');
$this->content = $content;
} }
return $this; return $this;
@@ -91,18 +91,18 @@ class VersionTag extends Tag
* Sets the version section of the tag. * Sets the version section of the tag.
* *
* @param string $version The new 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 * @return $this
*/ */
public function setVersion($version) public function setVersion($version)
{ {
$this->content = null;
$this->version $this->version
= preg_match('/^' . self::REGEX_VECTOR . '$/ux', $version) = preg_match('/^' . self::REGEX_VECTOR . '$/ux', $version)
? $version ? $version
: ''; : '';
$this->content = null;
return $this; return $this;
} }
} }