/** * Generate docblock. * * @param string $class * @param array $properties * @param array $methods * @return mixed */ public function docblock($class, $properties, $methods) { $phpdoc = new DocBlock(''); $phpdoc->setText($class); foreach ($properties as $property) { $tag = Tag::createInstance("@{$property['type']} {$property['return']} {$property['name']}", $phpdoc); $phpdoc->appendTag($tag); } foreach ($methods as $method) { $tag = Tag::createInstance("@method {$method['type']} {$method['return']} {$method['name']}({$method['arguments']})", $phpdoc); $phpdoc->appendTag($tag); } $serializer = new DocBlockSerializer(); $docComment = $serializer->getDocComment($phpdoc); return $docComment; }
/** * @param string $class * @return string */ protected function createPhpDocs($class) { $reflection = new \ReflectionClass($class); $namespace = $reflection->getNamespaceName(); $classname = $reflection->getShortName(); $originalDoc = $reflection->getDocComment(); if ($this->reset) { $phpdoc = new DocBlock('', new Context($namespace)); } else { $phpdoc = new DocBlock($reflection, new Context($namespace)); } if (!$phpdoc->getText()) { $phpdoc->setText($class); } $properties = array(); $methods = array(); foreach ($phpdoc->getTags() as $tag) { $name = $tag->getName(); if ($name == "property" || $name == "property-read" || $name == "property-write") { $properties[] = $tag->getVariableName(); } elseif ($name == "method") { $methods[] = $tag->getMethodName(); } } foreach ($this->properties as $name => $property) { $name = "\${$name}"; if (in_array($name, $properties)) { continue; } if ($property['read'] && $property['write']) { $attr = 'property'; } elseif ($property['write']) { $attr = 'property-write'; } else { $attr = 'property-read'; } $tag = Tag::createInstance("@{$attr} {$property['type']} {$name} {$property['comment']}", $phpdoc); $phpdoc->appendTag($tag); } foreach ($this->methods as $name => $method) { if (in_array($name, $methods)) { continue; } $arguments = implode(', ', $method['arguments']); $tag = Tag::createInstance("@method static {$method['type']} {$name}({$arguments})", $phpdoc); $phpdoc->appendTag($tag); } $serializer = new DocBlockSerializer(); $serializer->getDocComment($phpdoc); $docComment = $serializer->getDocComment($phpdoc); if ($this->write) { $filename = $reflection->getFileName(); $contents = \File::get($filename); if ($originalDoc) { $contents = str_replace($originalDoc, $docComment, $contents); } else { $needle = "class {$classname}"; $replace = "{$docComment}\nclass {$classname}"; $pos = strpos($contents, $needle); if ($pos !== false) { $contents = substr_replace($contents, $replace, $pos, strlen($needle)); } } if (\File::put($filename, $contents)) { $this->info('Written new phpDocBlock to ' . $filename); } } $output = "namespace {$namespace}{\n{$docComment}\n\tclass {$classname} {}\n}\n\n"; return $output; }
protected function createProperty(Tag $tag) { $name = trim($tag->getVariableName(), '$'); $prop = new ClassProperty(); $prop->name = $name; $prop->setType($this->getFQCN($tag->getType())); return $prop; }
/** * {@inheritdoc} */ public function setContent($content) { Tag::setContent($content); if (preg_match('/^ # File component (?: # File path in quotes \\"([^\\"]+)\\" | # File URI (\\S+) ) # Remaining content (parsed by SourceTag) (?:\\s+(.*))? $/sux', $this->description, $matches)) { if ('' !== $matches[1]) { $this->setFilePath($matches[1]); } else { $this->setFileURI($matches[2]); } if (isset($matches[3])) { parent::setContent($matches[3]); } else { $this->setDescription(''); } $this->content = $content; } return $this; }
/** * Parses a tag and populates the member variables. * * @param string $type Tag identifier for this tag (should be 'example'). * @param string $content Contents for this tag. * @param DocBlock $docblock The DocBlock which this tag belongs to. * @param Location $location Location of the tag. */ public function __construct($type, $content, DocBlock $docblock = null, Location $location = null) { Tag::__construct($type, $content, $docblock, $location); if (preg_match('/^ (?: # File path in quotes \\"([^\\"]+)\\" | # File URI (\\S+) ) # Remaining content (parsed by SourceTag) (?:\\s+(.*))? $/sux', $this->description, $matches)) { if ('' !== $matches[1]) { //Quoted file path. $this->filePath = trim($matches[1]); } elseif (false === strpos($matches[2], ':')) { //Relative URL or a file path with no spaces in it. $this->filePath = rawurldecode(str_replace(array('/', '\\'), '%2F', $matches[2])); } else { //Absolute URL or URI. $this->filePath = $matches[2]; } if (isset($matches[3])) { parent::__construct($type, $matches[3]); $this->content = $content; } else { $this->description = ''; } } }
/** * Parses a tag and populates the member variables. * * @param string $type Tag identifier for this tag (should be 'link'). * @param string $content Contents for this tag. * @param DocBlock $docblock The DocBlock which this tag belongs to. * @param Location $location Location of the tag. */ public function __construct($type, $content, DocBlock $docblock = null, Location $location = null) { parent::__construct($type, $content, $docblock, $location); $content = preg_split('/\\s+/u', $this->description, 2); // any output is considered a type $this->link = $content[0]; $this->description = isset($content[1]) ? $content[1] : $content[0]; }
/** * * @return \phpDocumentor\Reflection\DocBlock */ protected function getDocBlock() { if (!self::$registered) { Tag::registerTagHandler('requiresRight', '\\oat\\tao\\model\\controllerMap\\RequiresRightTag'); self::$registered = true; } return new DocBlock($this->method); }
/** * {@inheritdoc} */ public function setContent($content) { parent::setContent($content); $parts = preg_split('/\\s+/Su', $this->description, 2); $this->link = $parts[0]; $this->setDescription(isset($parts[1]) ? $parts[1] : $parts[0]); $this->content = $content; return $this; }
/** * {@inheritdoc} */ public function setContent($content) { parent::setContent($content); $parts = preg_split('/\\s+/Su', $this->description, 2); // any output is considered a type $this->refers = $parts[0]; $this->setDescription(isset($parts[1]) ? $parts[1] : ''); $this->content = $content; return $this; }
/** * Parses a tag and populates the member variables. * * @param string $type Tag identifier for this tag (should be 'author'). * @param string $content Contents for this tag. * @param DocBlock $docblock The DocBlock which this tag belongs to. * @param Location $location Location of the tag. */ public function __construct($type, $content, DocBlock $docblock = null, Location $location = null) { parent::__construct($type, $content, $docblock, $location); if (preg_match('/^([^\\<]*)(\\<([^\\>]*)\\>)?$/', $this->description, $matches)) { $this->name = trim($matches[1]); if (isset($matches[3])) { $this->email = trim($matches[3]); } } }
/** * {@inheritdoc} */ public function setContent($content) { parent::setContent($content); if (preg_match('/^(' . self::REGEX_AUTHOR_NAME . ')(\\<(' . self::REGEX_AUTHOR_EMAIL . ')\\>)?$/u', $this->description, $matches)) { $this->authorName = trim($matches[1]); if (isset($matches[3])) { $this->authorEmail = trim($matches[3]); } } return $this; }
/** * Registers all tags handlers. */ public static function registerTagHandlers() { static $isRegistered; if (!$isRegistered) { $mapping = ['query' => '\\pahanini\\restdoc\\tags\\QueryTag', 'field' => '\\phpDocumentor\\Reflection\\DocBlock\\Tag\\ParamTag', 'link' => '\\phpDocumentor\\Reflection\\DocBlock\\Tag\\ParamTag', 'label' => '\\phpDocumentor\\Reflection\\DocBlock\\Tag', 'extraField' => '\\phpDocumentor\\Reflection\\DocBlock\\Tag\\ParamTag', 'extraLink' => '\\phpDocumentor\\Reflection\\DocBlock\\Tag\\ParamTag']; foreach ($mapping as $suffix => $class) { $tagName = Doc::TAG_PREFIX . $suffix; Tag::registerTagHandler($tagName, $class); } } }
/** * {@inheritdoc} */ public function setContent($content) { Tag::setContent($content); // 1. none or more whitespace // 2. optionally the keyword "static" followed by whitespace // 3. optionally a word with underscores followed by whitespace : as // type for the return value // 4. then optionally a word with underscores followed by () and // whitespace : as method name as used by phpDocumentor // 5. then a word with underscores, followed by ( and any character // until a ) and whitespace : as method name with signature // 6. any remaining text : as description if (preg_match('/^ # Static keyword # Declates a static method ONLY if type is also present (?: (static) \\s+ )? # Return type (?: ([\\w\\|_\\\\]+) \\s+ )? # Legacy method name (not captured) (?: [\\w_]+\\(\\)\\s+ )? # Method name ([\\w\\|_\\\\]+) # Arguments \\(([^\\)]*)\\) \\s* # Description (.*) $/sux', $this->description, $matches)) { list(, $static, $this->type, $this->method_name, $this->arguments, $this->description) = $matches; if ($static) { if (!$this->type) { $this->type = 'static'; } else { $this->isStatic = true; } } else { if (!$this->type) { $this->type = 'void'; } } $this->parsedDescription = null; } else { echo date('c') . ' ERR (3): @method contained invalid contents: ' . $this->content . PHP_EOL; } return $this; }
/** * {@inheritdoc} */ public function setContent($content) { parent::setContent($content); $parts = preg_split('/\\s+/Su', $this->description, 3); if (count($parts) >= 2) { $this->parameter = $parts[0]; $this->rightId = $parts[1]; } $this->setDescription(isset($parts[2]) ? $parts[2] : ''); $this->content = $content; return $this; }
/** * {@inheritdoc} */ public function setContent($content) { Tag::setContent($content); $parts = preg_split('/\\s+/Su', $this->description, 2); $tmp = explode('=', array_shift($parts)); if (count($tmp) == 2) { $this->defaultValue = $tmp[1]; $this->variableName = $tmp[0]; } else { $this->variableName = $tmp[0]; } $this->setDescription(join(' ', str_replace("\n", " ", $parts))); return $this; }
/** * Perform post-registration booting of services. * * @return void */ public function boot() { // Registering custom tags Tag::registerTagHandler('apiParam', '\\phpDocumentor\\Reflection\\DocBlock\\Tag\\ParamTag'); // Set router RouteResolver::setRouter(app()->make('router')); // use this if your package needs a config file // $this->publishes([ // __DIR__.'/config/config.php' => config_path('skeleton.php'), // ]); // use the vendor configuration file as fallback // $this->mergeConfigFrom( // __DIR__.'/config/config.php', 'skeleton' // ); }
/** * Parses a tag and populates the member variables. * * @param string $type Tag identifier for this tag (should be 'var'). * @param string $content Contents for this tag. * @param DocBlock $docblock The DocBlock which this tag belongs to. * @param Location $location Location of the tag. */ public function __construct($type, $content, DocBlock $docblock = null, Location $location = null) { Tag::__construct($type, $content, $docblock, $location); $content = preg_split('/\\s+/u', $this->description); if (count($content) == 0) { return; } // var always starts with the variable name $this->type = array_shift($content); // if the next item starts with a $ it must be the variable name if (count($content) > 0 && strlen($content[0]) > 0 && $content[0][0] == '$') { $this->variableName = array_shift($content); } $this->description = implode(' ', $content); }
/** * Adds type information to the structure. * * @param string[] $types Array with types in any format; will be transformed * to FQCN. * * @todo Move this method to a better spot with namespace and alias access * (together with namespace and alias stuff). * * @return void */ public function setTypes($types) { foreach ($types as $type) { if ($type == '') { continue; } $type = trim($this->expandType($type)); // strip ampersands $name = str_replace('&', '', $type); $type_object = $this->xml->addChild('type', $name); // register whether this variable is by reference by checking // the first and last character $type_object['by_reference'] = substr($type, 0, 1) === '&' || substr($type, -1) === '&' ? 'true' : 'false'; } $this->xml['type'] = $this->expandType($this->tag->getType()); }
/** * {@inheritdoc} */ public function setContent($content) { parent::setContent($content); if (preg_match('/^ # The version vector (' . self::REGEX_VECTOR . ') \\s* # The description (.+)? $/sux', $this->description, $matches)) { $this->version = $matches[1]; $this->setDescription(isset($matches[2]) ? $matches[2] : ''); $this->content = $content; } return $this; }
/** * Parses a tag and populates the member variables. * * @param string $type Tag identifier for this tag (should be 'param'). * @param string $content Contents for this tag. * @param DocBlock $docblock The DocBlock which this tag belongs to. * @param Location $location Location of the tag. */ public function __construct($type, $content, DocBlock $docblock = null, Location $location = null) { Tag::__construct($type, $content, $docblock, $location); $content = preg_split('/(\\s+)/u', $this->description, 3, PREG_SPLIT_DELIM_CAPTURE); // 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] !== '$') { $this->type = array_shift($content); array_shift($content); } // if the next item starts with a $ it must be the variable name if (isset($content[0]) && strlen($content[0]) > 0 && $content[0][0] == '$') { $this->variableName = array_shift($content); array_shift($content); } $this->description = implode('', $content); }
/** * {@inheritdoc} */ public function setContent($content) { Tag::setContent($content); $parts = preg_split('/(\\s+)/Su', $this->description, 3, PREG_SPLIT_DELIM_CAPTURE); // if the first item that is encountered is not a variable; it is a type if (isset($parts[0]) && strlen($parts[0]) > 0 && $parts[0][0] !== '$') { $this->type = array_shift($parts); array_shift($parts); } #print_p($parts); // if the next item starts with a $ it must be the variable name if (isset($parts[0]) && strlen($parts[0]) > 0 && $parts[0][0] == '$') { $this->variableName = array_shift($parts); array_shift($parts); } $this->setDescription(implode('', $parts)); $this->content = $content; return $this; }
/** * {@inheritdoc} */ public function setContent($content) { Tag::setContent($content); $parts = preg_split('/(\\s+)/Su', $this->description, 3, PREG_SPLIT_DELIM_CAPTURE); // if the first item that is encountered is not a variable; it is a type if (isset($parts[0]) && strlen($parts[0]) > 0 && $parts[0][0] !== '$') { $this->type = array_shift($parts); array_shift($parts); } // if the next item starts with a $ or ...$ it must be the variable name if (isset($parts[0]) && strlen($parts[0]) > 0 && ($parts[0][0] == '$' || substr($parts[0], 0, 4) === '...$')) { $this->variableName = array_shift($parts); array_shift($parts); if (substr($this->variableName, 0, 3) === '...') { $this->isVariadic = true; $this->variableName = substr($this->variableName, 3); } } $this->setDescription(implode('', $parts)); $this->content = $content; return $this; }
/** * Parses a tag and populates the member variables. * * @param string $type Tag identifier for this tag (should be 'source'). * @param string $content Contents for this tag. * @param DocBlock $docblock The DocBlock which this tag belongs to. * @param Location $location Location of the tag. */ public function __construct($type, $content, DocBlock $docblock = null, Location $location = null) { parent::__construct($type, $content, $docblock, $location); if (preg_match('/^ # Starting line ([1-9]\\d*) \\s* # Number of lines (?: ((?1)) \\s+ )? # Description (.*) $/sux', $this->description, $matches)) { $this->startingLine = (int) $matches[1]; if (isset($matches[2]) && '' !== $matches[2]) { $this->lineCount = (int) $matches[2]; } $this->description = $matches[3]; } }
/** * Parses a tag and populates the member variables. * * @param string $type Tag identifier for this tag (should be 'method'). * @param string $content Contents for this tag. * @param DocBlock $docblock The DocBlock which this tag belongs to. * @param Location $location Location of the tag. */ public function __construct($type, $content, DocBlock $docblock = null, Location $location = null) { Tag::__construct($type, $content, $docblock, $location); $matches = array(); // 1. none or more whitespace // 2. optionally a word with underscores followed by whitespace : as // type for the return value // 3. then optionally a word with underscores followed by () and // whitespace : as method name as used by phpDocumentor // 4. then a word with underscores, followed by ( and any character // until a ) and whitespace : as method name with signature // 5. any remaining text : as description if (preg_match('/^ # Return type (?: ([\\w\\|_\\\\]+) \\s+ )? # Legacy method name (not captured) (?: [\\w_]+\\(\\)\\s+ )? # Method name ([\\w\\|_\\\\]+) # Arguments \\(([^\\)]*)\\) \\s* # Description (.*) $/sux', $this->description, $matches)) { list(, $this->type, $this->method_name, $this->arguments, $this->description) = $matches; if (!$this->type) { $this->type = 'void'; } } else { echo date('c') . ' ERR (3): @method contained invalid contents: ' . $this->content . PHP_EOL; } }
/** * Parses a tag and populates the member variables. * * @param string $type Tag identifier for this tag (should be 'version'). * @param string $content Contents for this tag. * @param DocBlock $docblock The DocBlock which this tag belongs to. * @param Location $location Location of the tag. */ public function __construct($type, $content, DocBlock $docblock = null, Location $location = null) { parent::__construct($type, $content, $docblock, $location); if (preg_match('/^ # The version vector ((?: # Normal release vectors. \\d\\S* | # VCS version vectors. Per PHPCS, they are expected to # follow the form of the VCS name, followed by ":", followed # by the version vector itself. # By convention, popular VCSes like CVS, SVN and GIT use "$" # around the actual version vector. [^\\s\\:]+\\:\\s*\\$[^\\$]+\\$ )) \\s* # The description (.+)? $/sux', $this->description, $matches)) { $this->version = $matches[1]; $this->description = isset($matches[2]) ? $matches[2] : ''; } }
/** * @param \ReflectionMethod $method * @param string $alias * @param string $class * @param string|null $methodName * @param array $interfaces */ public function __construct(\ReflectionMethod $method, $alias, $class, $methodName = null, $interfaces = array()) { $this->method = $method; $this->interfaces = $interfaces; $this->name = $methodName ?: $method->name; $this->namespace = $method->getDeclaringClass()->getNamespaceName(); //Create a DocBlock and serializer instance $this->phpdoc = new DocBlock($method, new Context($this->namespace)); //Normalize the description and inherit the docs from parents/interfaces try { $this->normalizeParams($this->phpdoc); $this->normalizeReturn($this->phpdoc); $this->normalizeDescription($this->phpdoc); } catch (\Exception $e) { } //Get the parameters, including formatted default values $this->getParameters($method); //Make the method static $this->phpdoc->appendTag(Tag::createInstance('@static', $this->phpdoc)); //Reference the 'real' function in the declaringclass $declaringClass = $method->getDeclaringClass(); $this->declaringClassName = '\\' . ltrim($declaringClass->name, '\\'); $this->root = '\\' . ltrim($class->getName(), '\\'); }
/** * {@inheritdoc} */ public function setContent($content) { parent::setContent($content); if (preg_match('/^ # Starting line ([1-9]\\d*) \\s* # Number of lines (?: ((?1)) \\s+ )? # Description (.*) $/sux', $this->description, $matches)) { $this->startingLine = (int) $matches[1]; if (isset($matches[2]) && '' !== $matches[2]) { $this->lineCount = (int) $matches[2]; } $this->setDescription($matches[3]); $this->content = $content; } return $this; }
/** * Formats the given tag to return a simple plain text version. * * @param Tag $tag * * @return string */ public function format(Tag $tag) { return '@' . $tag->getName() . ' ' . (string) $tag; }
/** * @param string $actualNamespace * @param Tag $tag * * @return string */ private function findType(Tag $tag, $actualNamespace, array $use, array $classes) { $rawType = $tag->getType(); if ($rawType === 'integer') { $rawType = 'int'; } $primitiveTypes = array('string', 'int', 'integer', 'float', 'double', 'bool', 'boolean', 'array', 'null', 'callable', 'scalar', 'void', 'object'); $excludedType = array('mixed', 'callable', 'callable[]', 'scalar', 'scalar[]', 'void', 'object', 'self', 'resource', 'true'); if (in_array($rawType, $excludedType) === true || count(explode('|', $rawType)) !== 1) { return array('value' => '', 'isClass' => false); } $arrayOfPrimitiveTypes = array_map(function ($val) { return $val . '[]'; }, $primitiveTypes); if (preg_match("/^[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*\$/", $rawType) === 0) { // this is a typo $this->logger->log(sprintf('Type "%s" does not exist in docblock', $rawType)); $type = array('value' => '', 'isClass' => false); } elseif (in_array(strtolower($rawType), $primitiveTypes)) { $type = array('value' => strtolower($rawType), 'isClass' => false); } elseif (in_array(strtolower($rawType), $arrayOfPrimitiveTypes)) { $type = array('value' => strtolower($rawType), 'isClass' => false); } else { // considered as class $type = array('value' => $rawType, 'isClass' => true); } return $type; }
/** * 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; }