Source for file Converter.inc
Documentation is available at Converter.inc
* Base class for all Converters
* phpDocumentor :: automatic documentation generator
* Copyright (c) 2001-2006 Gregory Beaver
* This library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* @author Greg Beaver <cellog@php.net>
* @copyright 2001-2006 Gregory Beaver
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoc.org
* @link http://pear.php.net/PhpDocumentor
* @see parserDocBlock, parserInclude, parserPage, parserClass
* @see parserDefine, parserFunction, parserMethod, parserVar
include_once("phpDocumentor/Smarty-2.6.0/libs/Smarty.class.php");
* Base class for all output converters.
* The Converter marks the final stage in phpDocumentor. phpDocumentor works
* <pre>Parsing => Intermediate Parsing organization => Conversion to output</pre>
* A Converter takes output from the {@link phpDocumentor_IntermediateParser} and
* converts it to output. With version 1.2, phpDocumentor includes a variety
* <li>{@link HTMLframesConverter}</li>
* <li>{@link HTMLSmartyConverter}</li>
* <li>{@link PDFdefaultConverter}</li>
* <li>{@link CHMdefaultConverter}</li>
* <li>{@link CSVdia2codeConverter}</li>
* <li>{@link XMLDocBookConverter}</li>
* The converter takes output directly from {@link phpDocumentor_IntermediateParser}
* and using {@link walk()} or {@link walk_everything} (depending on the value of
* {@link $sort_absolutely_everything}) it "walks" over an array of phpDocumentor elements.}}}
* @author Greg Beaver <cellog@php.net>
* This converter knows about the new root tree processing
* In order to fix PEAR Bug #6389
* output format of this converter
* in Child converters, this will match the first part of the -o command-line
* as in -o HTML:frames:default "HTML"
* @tutorial phpDocumentor.howto.pkg#using.command-line.output
* package name currently being converted
* subpackage name currently being converted
* set to a classname if currently parsing a class, false if not
* the workhorse of linking.
* This array is an array of link objects of format:
* [package][subpackage][eltype][elname] = descendant of {@link abstractLink}
* eltype can be page|function|define|class|method|var
* if eltype is method or var, the array format is:
* [package][subpackage][eltype][class][elname]
* @see functionLink, pageLink, classLink, defineLink, methodLink, varLink, globalLink
* the workhorse of linking, with allowance for support of multiple
* elements in different files.
* This array is an array of link objects of format:
* [package][subpackage][eltype][file][elname] = descendant of {@link abstractLink}
* eltype can be function|define|class|method|var
* if eltype is method or var, the array format is:
* [package][subpackage][eltype][file][class][elname]
* @see functionLink, pageLink, classLink, defineLink, methodLink, varLink, globalLink
var $linkswithfile = array ();
* set to value of -po commandline
* @tutorial phpDocumentor.howto.pkg#using.command-line.packageoutput
* name of current page being converted
* path of current page being converted
* template for the procedural page currently being processed
* template for the class currently being processed
* current procedural page being processed
* alphabetical index of all elements sorted by package, subpackage, page,
* @var array Format: array(package => array(subpackage => array('page'|'class' => array(path|classname => array(element, element,...)))))
* @uses $sort_absolutely_everything if true, then $package_elements is used,
* otherwise, the {@link ParserData::$classelements} and
* {@link ParserData::$pageelements} variables are used
* alphabetical index of all elements
* @var array Format: array(first letter of element name => array({@link parserElement} or {@link parserPage},...))
* @see formatIndex(), HTMLframesConverter::formatIndex()
* alphabetized index of procedural pages by package
* @var array Format: array(package => array(subpackage => array({@link pageLink} 1,{@link pageLink} 2,...)
* alphabetized index of defines by package
* @var array Format: array(package => array(subpackage => array({@link defineLink} 1,{@link defineLink} 2,...)
* alphabetized index of classes by package
* @var array Format: array(package => array(subpackage => array({@link classLink} 1,{@link classLink} 2,...)
* alphabetized index of global variables by package
* @var array Format: array(package => array(subpackage => array({@link globalLink} 1,{@link globalLink} 2,...)
* alphabetized index of functions by package
* @var array Format: array(package => array(subpackage => array({@link functionLink} 1,{@link functionLink} 2,...)
* alphabetical index of all elements, indexed by package/subpackage
* @var array Format: array(first letter of element name => array({@link parserElement} or {@link parserPage},...))
* @see formatPkgIndex(), HTMLframesConverter::formatPkgIndex()
* alphabetical index of all elements on a page by package/subpackage
* The page itself has a link under ###main
* @var array Format: array(package => array(subpackage => array(path => array({@link abstractLink} descendant 1, ...)))
* This determines whether the {@link $page_contents} array should be sorted by element type as well as alphabetically by name
* @see sortPageContentsByElementType()
* This is used if the content must be passed in the order it should be read, i.e. by package, procedural then classes
* This fixes bug 637921, and is used by {@link PDFdefaultConverter}
* alphabetical index of all methods and vars in a class by package/subpackage
* The class itself has a link under ###main
* array({@link abstractLink} descendant 1, ...
* controls processing of elements marked private with @access private
* defaults to false. Set with command-line --parseprivate or -pp
* controls display of progress information while parsing.
* defaults to false. Set to true for cron jobs or other situations where no visual output is necessary
* directory that output is sent to. -t command-line sets this.
* @tutorial phpDocumentor.howto.pkg#using.command-line.target
* Directory that the template is in, relative to phpDocumentor root directory
* Directory that the smarty templates are in
* Name of the template, from last part of -o
* @tutorial phpDocumentor.howto.pkg#using.command-line.output
* full path of the current file being converted
* All class information, organized by path, and by package
* Flag used to help converters determine whether to do special source highlighting
* Every package that contains classes may have parent or child classes
* in other packages. In other words, this code is legal:
* class two extends one {}
* In this case, package one is a parent of package two
* @see phpDocumentor_IntermediateParser::$package_parents
* Packages associated with categories
* Used by the XML:DocBook/peardoc2 converter, and available to others, to
* group many packages into categories
* @see phpDocumentor_IntermediateParser::$packagecategories
* All packages encountered in parsing
* @see phpDocumentor_IntermediateParser::$all_packages
* A list of files that have had source code generated
* Controls which of the one-element-only indexes are generated.
* Generation of these indexes for large packages is time-consuming. This is an optimization feature. An
* example of how to use this is in {@link HTMLframesConverter::$leftindex}, and in {@link HTMLframesConverter::formatLeftIndex()}.
* These indexes are intended for use as navigational aids through documentation, but can be used for anything by converters.
* @see $class_elements, $page_elements, $function_elements, $define_elements, $global_elements
var $leftindex = array ('classes' => true , 'pages' => true , 'functions' => true , 'defines' => true , 'globals' => true );
* @see phpDocumentor_IntermediateParser::$title
var $title = 'Generated Documentation';
* @see phpDocumentor_IntermediateParser::$charset
* Options for each template, parsed from the options.ini file in the template base directory
* @tutorial phpDocumentor/tutorials.pkg#conversion.ppage
* Tutorials and Extended Documentation parsed from a tutorials/package[/subpackage] directory
* @tutorial tutorials.pkg
var $tutorials = array ();
* tree-format structure of tutorials and their child tutorials, if any
var $tutorial_tree = false;
* list of tutorials that have already been processed. Used by @link _setupTutorialTree()
var $processed_tutorials;
* List of all @todo tags and a link to the element with the @todo
* Format: array(package => array(link to element, array(todo {@link parserTag},...)),...)
* @tutorial tags.todo.pkg
* Directory where compiled templates go - will be deleted on exit
var $_compiledDir = array ();
* Initialize Converter data structures
* @param array {@link $all_packages} value
* @param array {@link $package_parents} value
* @param Classes {@link $classes} value
* @param ProceduralPages {@link $proceduralpages} value
* @param array {@link $package_output} value
* @param boolean {@link $parseprivate} value
* @param boolean {@link $quietmode} value
* @param string {@link $targetDir} value
* @param string {@link $templateDir} value
* @param string (@link $title} value
* @param string (@link $charset} value
function Converter(&$allp, &$packp, &$classes, &$procpages, $po, $pp, $qm, $targetDir, $template, $title, $charset)
$this->package = $GLOBALS['phpDocumentor_DefaultPackageName'];
$this->proceduralpages = &$procpages;
$this->setTargetdir ($targetDir);
* Called by IntermediateParser after creation
function setTutorials ($tutorials)
$this->tutorials = $tutorials;
* @param pkg|cls|procthe tutorial type to search for
* @param string package name
* @param string subpackage name, if any
* @return false|parserTutorialif the tutorial exists, return it
function hasTutorial($type, $name, $package, $subpackage = '')
if (isset ($this->tutorials[$package][$subpackage][$type][$name . '.' . $type]))
return $this->tutorials[$package][$subpackage][$type][$name . '.' . $type];
* Called by {@link walk()} while converting, when the last class element
* A Converter can use this method in any way it pleases. HTMLframesConverter
* uses it to complete the template for the class and to output its
* @see HTMLframesConverter::endClass()
* Called by {@link walk()} while converting, when the last procedural page
* element has been parsed.
* A Converter can use this method in any way it pleases. HTMLframesConverter
* uses it to complete the template for the procedural page and to output its
* @see HTMLframesConverter::endClass()
* Called by {@link walk()} while converting.
* This method is intended to be the place that {@link $pkg_elements} is
* @see HTMLframesConverter::formatPkgIndex()
* Called by {@link walk()} while converting.
* This method is intended to be the place that {@link $elements} is
* @see HTMLframesConverter::formatIndex()
* Called by {@link walk()} while converting.
* This method is intended to be the place that any of
* {@link $class_elements, $function_elements, $page_elements},
* {@link $define_elements}, and {@link $global_elements} is formatted for
* output, depending on the value of {@link $leftindex}
* @see HTMLframesConverter::formatLeftIndex()
* Called by {@link parserSourceInlineTag::stringConvert()} to allow
* converters to format the source code the way they'd like.
* default returns it unchanged (html with xhtml tags)
* @param string output from highlight_string() - use this function to
* reformat the returned data for Converter-specific output
* @deprecated in favor of tokenizer-based highlighting. This will be
* Initialize highlight caching
$this->_highlightCache = array (false , false );
$this->_appendHighlight = '';
return $this->_highlightCache;
function _setHighlightCache ($type, $token)
$test = ($this->_highlightCache[0 ] === $type && $this->_highlightCache[1 ] == $token);
$this->_appendHighlight = '';
$this->_highlightCache = array ($type, $token);
* Return the close text for the current token
$hc = $this->_highlightCache;
$this->_highlightCache = array (false , false );
* Used to allow converters to format the source code the way they'd like.
* default returns it unchanged. Mainly used by the {@link HighlightParser}
* The method takes information from options.ini, the template options
* file, specifically the [highlightSourceTokens] and [highlightSource]
* sections, and uses them to enclose tokens.
* @param integer token value from {@link PHP_MANUAL#tokenizer tokenizer constants}
* @param string contents of token
* @param boolean whether the contents are preformatted or need modification
if ($this->_setHighlightCache ('highlightSourceTokens', token_name($token))) {
$e = $this->_appendHighlight;
$this->_setHighlightCache (false , false );
$e = $this->_appendHighlight;
$newword = ($preformatted ? $word : $this->postProcess($word));
if ($this->_setHighlightCache ('highlightSource', $word)) {
$e = $this->_appendHighlight;
$this->_setHighlightCache (false , false );
$e = $this->_appendHighlight;
return $e . ($preformatted ? $word : $this->postProcess($word));
* Used to allow converters to format the source code of DocBlocks the way
* default returns it unchanged. Mainly used by the {@link HighlightParser}
* The method takes information from options.ini, the template options
* file, specifically the [highlightDocBlockSourceTokens] section, and uses
* @param string name of docblock token type
* @param string contents of token
* @param boolean whether the contents are preformatted or need modification
$this->_setHighlightCache (false , false );
$e = $this->_appendHighlight;
if ($this->_setHighlightCache ('highlightDocBlockSourceTokens', $token)) {
$e = $this->_appendHighlight;
return $e . $this->template_options['highlightDocBlockSourceTokens'][$token] . $word;
$this->_setHighlightCache (false , false );
$e = $this->_appendHighlight;
return $e . ($preformatted ? $word : $this->postProcess($word));
* Used to allow converters to format the source code of Tutorial XML the way
* default returns it unchanged. Mainly used by the {@link HighlightParser}
* The method takes information from options.ini, the template options
* file, specifically the [highlightDocBlockSourceTokens] section, and uses
* @param string name of docblock token type
* @param string contents of token
* @param boolean whether the contents are preformatted or need modification
$this->_setHighlightCache (false , false );
$e = $this->_appendHighlight;
if ($this->_setHighlightCache ('highlightTutorialSourceTokens', $token)) {
$e = $this->_appendHighlight;
return $e . $this->template_options['highlightTutorialSourceTokens'][$token] . $word;
$this->_setHighlightCache (false , false );
$e = $this->_appendHighlight;
return $e . ($preformatted ? $word : $this->postProcess($word));
* Called by {@link parserReturnTag::Convert()} to allow converters to
* change type names to desired formatting
* Used by {@link XMLDocBookConverter::type_adjust()} to change true and
* false to the peardoc2 values
* Used to convert the {@}example} inline tag in a docblock.
* By default, this just wraps ProgramExample
* @see XMLDocBookpeardoc2Converter::exampleProgramExample
* @param boolean true if this is to highlight a tutorial <programlisting>
$class = null /*false*/, $linenum = null /*false*/, $filesourcepath = null /*false*/)
return $this->ProgramExample($example, $tutorial, $inlinesourceparse, $class, $linenum, $filesourcepath);
* Used to convert the <<code>> tag in a docblock
* @param boolean true if this is to highlight a tutorial <programlisting>
function ProgramExample($example, $tutorial = false , $inlinesourceparse = null /*false*/,
$class = null /*false*/, $linenum = null /*false*/, $filesourcepath = null /*false*/)
$e = $obj->getFileSource ();
foreach ($e as $ke => $ee)
foreach ($ee as $kee => $eee)
if ((int) $e[$ke][$kee][0 ] == T_OPEN_TAG )
$example = "<?php\n". $example;
$e = $obj->getFileSource ();
$saveclass = $this->class;
if (!isset ($inlinesourceparse))
$example = $parser->parse ($e, $this, true ); // force php mode
if (isset ($filesourcepath))
$example = $parser->parse ($e, $this, $inlinesourceparse, $class, $linenum, $filesourcepath);
} elseif (isset ($linenum))
$example = $parser->parse ($e, $this, $inlinesourceparse, $class, $linenum);
$example = $parser->parse ($e, $this, $inlinesourceparse, $class);
$example = $parser->parse ($e, $this, $inlinesourceparse);
$this->class = $saveclass;
$x = $parse->parse ($example, $this);
* Used to convert the contents of <<li>> in a docblock
* Used to convert the contents of <<ol>> or <<ul>> in a docblock
$listname = ($ordered ? 'ol' : 'ul');
if (!isset ($this->template_options['desctranslate']['/'. $listname])) return $list;
* Used to convert the contents of <<pre>> in a docblock
* Used to enclose a paragraph in a docblock
* Used to convert the contents of <<b>> in a docblock
* Used to convert the contents of <<i>> in a docblock
* Used to convert the contents of <<var>> in a docblock
* Used to convert the contents of <<kbd>> in a docblock
* Used to convert the contents of <<samp>> in a docblock
* Used to convert <<br>> in a docblock
* This version does nothing
* Perform necessary post-processing of string data. For example, the HTML
* Converters should escape < and > to become < and >
* Creates a table of contents for a {@}toc} inline tag in a tutorial
* This function should return a formatted table of contents. By default, it
* does nothing, it is up to the converter to format the TOC
* @return string table of contents formatted for use in the current output format
* @param array format: array(array('tagname' => section, 'link' => returnsee link, 'id' => anchor name, 'title' => from title tag),...)
* Write out the formatted source code for a php file
* This function provides the primary functionality for the
* {@tutorial tags.filesource.pkg} tag.
* @param string full path to the file
* @param string fully highlighted/linked source code of the file
* Write out the formatted source code for an example php file
* This function provides the primary functionality for the
* {@tutorial tags.example.pkg} tag.
* @param string example title
* @param string example filename (no path)
* @param string fully highlighted/linked source code of the file
/** Translate the path info into a unique file name for the highlighted
* @param string $pathinfo
global $_phpDocumentor_options;
$pathinfo = $this->proceduralpages->getPathInfo ($path, $this);
$pathinfo['source_loc'] = str_replace($_phpDocumentor_options['Program_Root']. '/','',$pathinfo['source_loc']);
$pathinfo['source_loc'] = str_replace('/','_',$pathinfo['source_loc']);
return " fsource_{$pathinfo['package']}_{$pathinfo['subpackage']}_{$pathinfo['source_loc']}";
/** Return the fixed path to the source-code file folder.
* @param string $base Path is relative to this folder
return $base . '__filesource';
/** Return the path to the current
* @param string $pathinfo
* @return string an output-format dependent link to phpxref-style highlighted
* @return string Link to the current page being parsed.
* Should return {@link $curname} and a converter-specific extension.
* Return a line of highlighted source code with formatted line number
* If the $path is a full path, then an anchor to the line number will be
* @param integer line number
* @param string highlighted source code line
* @param false|stringfull path to @filesource file this line is a part of,
* if this is a single line from a complete file.
* @return string formatted source code line with line number
function sourceLine($linenumber, $line, $path = false )
return $this->getSourceAnchor ($path, $linenumber) .
* Determine whether an element's file has generated source code, used for
* linking to line numbers of source.
* Wrapper for {@link $sourcePaths} in this version
* {@internal since file paths get stored with most/all slashes
* set to forward slash '/', we need to doublecheck that
* we're not given a backslashed path to search for...
* if we are, it's likely that it was originally stored
* with a forward slash. Further, I'm not convinced it's safe
* to just check the {@link PHPDOCUMENTOR_WINDOWS} flag, so I'm checking
* specifically for backslashes intead.}}}
* @param string full path to the source code file
if (strpos($path, '\\') > -1 ) {
* Mark a file as having had source code highlighted
* @param string full path of source file
* Used to translate an XML DocBook entity like ” from a tutorial by
* reading the options.ini file for the template.
* @param string entity name
* Used to translate an XML DocBook tag from a tutorial by reading the
* options.ini file for the template.
* @param string any attributes Format: array(name => value)
* @param string the tag contents, if any
* @param string the tag contents, if any, unpost-processed
return '<'. $name. $this->AttrToString($name,$attr,true ). '>'. $cdata. '</'. $name. '>'. "\n";
// make sure this template transforms the tag into something
// test for global attribute transforms like $attr$role = class, changing
// all role="*" attributes to class="*" in html, for example
foreach($attr as $att => $val)
{// if the close tag isn't specified, we put opening and closing tags around it, with translated attributes
{ // if close tag is specified, use the open and close as literal
if ($name == 'programlisting' && isset ($attr['role']) &&
($attr['role'] == 'php' || $attr['role'] == 'tutorial' ||
$attr['role'] == 'html' || $attr['role'] == 'xml') )
{ // highlight PHP source
// var_dump($unconvertedcdata, $cdata);exit;
if ($attr['role'] == 'php') {
} elseif ($attr['role'] == 'tutorial') {
} elseif ($attr['role'] == 'html') {
$cdata = $unconvertedcdata;
} elseif ($attr['role'] == 'xml') {
return '<'. $name. $this->AttrToString($name,$attr,true ). '>' . $cdata .
* Convert the attribute of a Tutorial docbook tag's attribute list
* to a string based on the template options.ini
* @param boolean if true, returns attrname="value"...
foreach($attr as $n => $v)
$ret .= $n. ' = "'. $v. '"';
// no_attr tells us to ignore all attributes
// tagname! tells us to ignore all attributes for this tag
if (count($attr)) $ret = ' ';
// pass 1, check to see if any attributes add together
foreach($attr as $n => $v)
foreach($attr as $n => $v)
{ // only 1 attribute translated for this one
// this is useful for equivalent value names
{ // more than 1 attribute combines to make the new attribute
$teststrtemp[] = $oldattr. '+'. $attr[$oldattr];
for($j= $i; !$started || $j != $i; $j = ($j + $i) % $num)
if (!empty ($a)) $a .= '|';
foreach($teststrs as $test)
$ret .= $n. ' = "'. $v. '"';
* Convert the title of a Tutorial docbook tag section
* to a string based on the template options.ini
* @param string title text
} else $cdata = $title. $cdata;
return array ($attr,$cdata);
* Return a converter-specific id to distinguish tutorials and their
return $package. $subpackage. $tutorial. $id;
* Create the {@link $elements, $pkg_elements} and {@link $links} arrays
* @todo version 2.0 - faulty package_output logic should be removed
* in this version, if the parent file isn't in the package, all
* the procedural elements are simply shunted to another package!
function _createPkgElements (&$pages)
foreach($pages as $j => $flub)
$this->package = $pages[$j]->parent ->package;
$this->subpackage = $pages[$j]->parent ->subpackage;
$this->curfile = $pages[$j]->parent ->getFile ();
$this->curname = $this->getPageName ($pages[$j]->parent );
$this->curpath = $pages[$j]->parent ->getPath ();
$this->addElement ($pages[$j]->parent ,$pages[$j]);
if (count($pages[$j]->classelements ))
$pages[$j]->parent ->subpackage = '';
$this->addElement ($pages[$j]->parent ,$pages[$j]);
$this->addElement ($pages[$j]->parent ,$pages[$j]);
for($i=0; $i< count($pages[$j]->elements ); $i++ )
$pages[$j]->elements [$i]->docblock ->package = $this->package;
$pages[$j]->elements [$i]->docblock ->subpackage = $this->subpackage;
$this->proceduralpages->replaceElement ($pages[$j]->elements [$i]);
$this->addElement ($pages[$j]->elements [$i]);
for($i=0; $i< count($pages[$j]->classelements ); $i++ )
if ($pages[$j]->classelements [$i]->type == 'class')
if ($this->checkKillClass ($pages[$j]->classelements [$i]->getName (),$pages[$j]->classelements [$i]->getPath ())) continue;
$this->package = $pages[$j]->classelements [$i]->docblock ->package;
$this->subpackage = $pages[$j]->classelements [$i]->docblock ->subpackage;
$this->class = $pages[$j]->classelements [$i]->name;
if ($this->killclass) continue;
// force all contained elements to have parent package/subpackage
$pages[$j]->classelements [$i]->docblock ->package = $this->package;
$pages[$j]->classelements [$i]->docblock ->subpackage = $this->subpackage;
if ($pages[$j]->classelements [$i]->type == 'class')
if ($this->checkKillClass ($pages[$j]->classelements [$i]->getName (),$pages[$j]->classelements [$i]->getPath ())) continue;
$this->package = $pages[$j]->classelements [$i]->docblock ->package;
$this->subpackage = $pages[$j]->classelements [$i]->docblock ->subpackage;
$this->class = $pages[$j]->classelements [$i]->name;
if (!$this->killclass) $this->addElement ($pages[$j]->classelements [$i]);
* Process the {@link $tutorials} array
* Using the tutorialname.ext.ini files, this method sets up tutorial
* hierarchy. There is some minimal error checking to make sure that no
* tutorial links to itself, even two levels deep as in tute->next->tute.
* If all tests pass, it creates the hierarchy
* @uses generateTutorialOrder()
* @uses _setupTutorialTree()
function _processTutorials ()
$parents = $all = array ();
foreach($this->tutorials as $package => $els)
unset ($this->tutorials[$package]);
unset ($this->tutorials[$package]);
foreach($els as $subpackage => $els2)
foreach($els2 as $type => $tutorials)
foreach($tutorials as $tutorial)
if (isset ($tutorial->ini ['Linked Tutorials']))
foreach($tutorial->ini ['Linked Tutorials'] as $child)
$sub = (empty ($tutorial->subpackage ) ? '' : $tutorial->subpackage . '/');
$kid = $tutorial->package . '/' . $sub . $child . '.' . $tutorial->tutorial_type;
// parent includes self as a linked tutorial?
$kidlink = $this->getTutorialLink($kid,false ,false ,array ($tutorial->package ));
$all[$package][$subpackage][$type][] = $tutorial;
// loop error-checking, use this to eliminate possibility of accidentally linking to a parent as a child
foreach($parents as $parent)
$testlinks[$parent->name ]['links'][] = $parent->getLink ($this);
$testlinks[$parent->name ]['name'][$parent->getLink ($this)] = $parent->name;
// generate the order of tutorials, and link them together
foreach($parents as $parent)
foreach($parent->ini ['Linked Tutorials'] as $child)
$sub = (empty ($parent->subpackage ) ? '' : $parent->subpackage . '/');
$kid = $parent->package . '/' . $sub . $child . '.' . $parent->tutorial_type;
// child tutorials must be in the same package AND subpackage
// AND have the same extension as the parent, makes things clearer for both ends
addErrorDie(PDERROR_TUTORIAL_IS_OWN_GRANDPA,$testlinks[$parent->name ][$this->returnSee($this->getTutorialLink($kid,false ,false ,array ($parent->package )))],$kid->name ,$testlinks[$parent->name ][$this->returnSee($this->getTutorialLink($kid,false ,false ,array ($parent->package )))],$kid->name. '.ini');
$new = $tree = $roots = array ();
// build a list of all 'root' tutorials (tutorials without parents).
foreach($parents as $i => $parent)
if (! $parent->isChildOf ($parents)) {
// add the parents and all child tutorials in order to the list of tutorials to process
foreach($parents as $parent)
$this->generateTutorialOrder ($parent,$all,$new);
// add the leftover tutorials
foreach($all as $package => $els)
foreach($els as $subpackage => $els2)
foreach($els2 as $type => $tutorials)
foreach($tutorials as $tutorial)
$new[$package][$subpackage][$type][] = $tutorial;
// remove the old, unprocessed tutorials, and set it up with the next code
$this->tutorials = array ();
// reset integrity of the tutorial list
// debug($this->vardump_tree($new));exit;
foreach($new as $package => $els)
foreach($els as $subpackage => $els2)
foreach($els2 as $type => $tutorials)
foreach($tutorials as $tutorial)
$this->tutorials[$prevpackage][$prevsubpackage][$prevtype][$prevname]->setNext ($tutorial,$this);
$tutorial->setPrev ($prev,$this);
$this->tutorials[$package][$subpackage][$type][$tutorial->name ] = $tutorial;
$prev = $tutorial->getLink ($this,true );
$prevsubpackage = $subpackage;
$prevname = $tutorial->name;
$this->tutorial_tree = $this->_setupTutorialTree ();
* called by {@link phpDocumentor_IntermediateParser::Convert()} to traverse
* the array of pages and their elements, converting them to the output format
* The walk() method should be flexible enough such that it never needs
* modification. walk() sets up all of the indexes, and sorts everything in
* logical alphabetical order. It then passes each element individually to
* {@link Convert()}, which then passes to the Convert*() methods. A child
* Converter need not override any of these unless special functionality must
* be added. see {@tutorial Converters/template.vars.cls} for details.
* walk() first creates all of the indexes {@link $elements, $pkg_elements}
* and the left indexes specified by {@link $leftindexes},
* and then sorts them by calling {@link sortIndexes()}.
* Next, it converts all README/CHANGELOG/INSTALL-style files, using
* passes all package-level docs to Convert(). Then, it calls the index
* sorting functions {@link formatPkgIndex(), formatIndex()} and
* {@link formatLeftIndex()}.
* Finally, it converts each procedural page in alphabetical order. This
* stage passes elements from the physical file to Convert() in alphabetical
* order. First, procedural page elements {@link parserDefine, parserInclude}
* {@link parserGlobal}, and {@link parserFunction} are passed to Convert().
* Then, class elements are passed in this order: {@link parserClass}, then
* all of the {@link parserVar}s in the class and all of the
* {@link parserMethod}s in the class. Classes are in alphabetical order,
* and both vars and methods are in alphabetical order.
* Finally, {@link ConvertErrorLog()} is called and the data walk is complete.}}}
* @param array Format: array(fullpath => {@link parserData} structure with full {@link parserData::$elements}
* and {@link parserData::$class_elements}.
* @param array Format: array({@link parserPackagePage} 1, {@link parserPackagePage} 2,...)
* @uses Converter::_createPkgElements() sets up {@link $elements} and
* {@link $pkg_elements} array, as well as {@link $links}
function walk(&$pages,&$package_pages)
die ("<b>ERROR</b>: nothing parsed");
$this->_createPkgElements ($pages);
foreach($this->ric as $name => $contents)
foreach($package_pages as $i => $perp)
phpDocumentor_out('Converting package page for package '. $package_pages[$i]->package. '... ');
$this->package = $package_pages[$i]->package;
$this->Convert($package_pages[$i]);
// get tutorials into the order they will display, and set next/prev links
$new = $this->_processTutorials ();
foreach($this->tutorials as $package => $els)
foreach($els as $subpackage => $els2)
foreach($els2 as $type => $tutorials)
foreach($tutorials as $tutorial)
if (!empty ($tutorial->subpackage ))
$ptext = " Converting ${a}Package-level tutorial ". $tutorial->name. '...';
$ptext = " Converting ${a}Class-level tutorial " . $tutorial->name . " and associating...";
$addend = 'unsuccessful ';
if (isset ($this->package_elements[$tutorial->package ][$tutorial->subpackage ]['class'][$link->name ]))
$this->package_elements[$tutorial->package ][$tutorial->subpackage ]['class'][$link->name ][0 ]->addTutorial ($tutorial,$this);
$addend = 'unsuccessful ';
foreach($pages as $j => $inf)
foreach($inf->classelements as $i => $class)
if ($class->type == 'class' && $class->name == str_replace('.cls','',$tutorial->name ) && $class->path == $link->path )
$pages[$j]->classelements [$i]->addTutorial ($tutorial,$this);
} else $ptext .= "unsuccessful ";
$ptext = " Converting ${a}Procedural-level tutorial ". $tutorial->name. " and associating...";
$addend = 'unsuccessful ';
if (isset ($this->package_elements[$tutorial->package ][$tutorial->subpackage ]['page'][$link->path ]))
$this->package_elements[$tutorial->package ][$tutorial->subpackage ]['page'][$link->path ][0 ]->addTutorial ($tutorial,$this);
foreach($pages as $j => $info)
$pages[$j]->addTutorial ($tutorial,$this);
} else $ptext .= "unsuccessful ";
$this->package = $tutorial->package;
foreach($pages as $j => $flub)
$this->package = $pages[$j]->parent ->package;
$this->subpackage = $pages[$j]->parent ->subpackage;
$this->curfile = $pages[$j]->parent ->getFile ();
$this->curname = $this->getPageName ($pages[$j]->parent );
$this->curpath = $pages[$j]->parent ->getPath ();
for($i=0; $i< count($pages[$j]->elements ); $i++ )
$a = $pages[$j]->elements [$i]->docblock ->getKeyword ('access');
// phpDocumentor_out(" ".$pages[$j]->elements[$i]->name."\n");
$pages[$j]->elements [$i]->docblock ->package = $this->package;
$pages[$j]->elements [$i]->docblock ->subpackage = $this->subpackage;
$this->Convert($pages[$j]->elements [$i]);
for($i=0; $i< count($pages[$j]->classelements ); $i++ )
if ($pages[$j]->classelements [$i]->type == 'class')
if (!$this->killclass) $this->endClass();
$this->killclass = false;
if ($this->checkKillClass ($pages[$j]->classelements [$i]->getName (),$pages[$j]->classelements [$i]->getPath ())) continue;
$this->package = $pages[$j]->classelements [$i]->docblock ->package;
$this->subpackage = $pages[$j]->classelements [$i]->docblock ->subpackage;
$this->class = $pages[$j]->classelements [$i]->name;
$a = $pages[$j]->classelements [$i]->docblock ->getKeyword ('access');
if ($this->killclass) continue;
// force all contained elements to have parent package/subpackage
$pages[$j]->classelements [$i]->docblock ->package = $this->package;
$pages[$j]->classelements [$i]->docblock ->subpackage = $this->subpackage;
if ($pages[$j]->classelements [$i]->type == 'class')
$this->killclass = false;
if ($this->checkKillClass ($pages[$j]->classelements [$i]->getName (),$pages[$j]->classelements [$i]->getPath ())) continue;
$this->package = $pages[$j]->classelements [$i]->docblock ->package;
$this->subpackage = $pages[$j]->classelements [$i]->docblock ->subpackage;
$this->class = $pages[$j]->classelements [$i]->name;
if ($this->killclass) continue;
// phpDocumentor_out(" ".$pages[$j]->classelements[$i]->name."\n");
$this->Convert($pages[$j]->classelements [$i]);
if (count($pages[$j]->classelements ) && !$this->killclass) $this->endClass();
* Get a tree structure representing the hierarchy of tutorials
* Returns an array in format:
* array('tutorial' => {@link parserTutorial},
* 'kids' => array( // child tutorials
* array('tutorial' => child {@link parserTutorial},
* @param parserTutorial|array
* @tutorial tutorials.pkg
$path = $this->_tutorial_path ($tutorial,$tutorial,$tutorial);
if (isset ($this->tutorial_tree[$path])) {
$tutorial = $this->tutorial_tree[$path];
if (isset ($tutorial['tutorial']))
$tree['tutorial'] = $tutorial['tutorial'];
if (isset ($tutorial['child']))
foreach($tutorial['child'] as $a => $b)
'tutorial' => $this->tutorials
[$btut->package ][$btut->subpackage ]
[$btut->tutorial_type ][$btut->name ]
$res['kids'] = $tempres['kids'];
* Remove tutorials one by one from $all, and transfer them into $new in the
* order they should be parsed
function generateTutorialOrder ($parent,&$all,&$new)
// remove from the list of tutorials to process
foreach($all[$parent->package ][$parent->subpackage ][$parent->tutorial_type ] as $ind => $t)
if ($t->name == $parent->name ) {
unset ($all[$parent->package ][$parent->subpackage ][$parent->tutorial_type ][$ind]);
// add to the new ordered list of tutorials
$x = &$new[$parent->package ][$parent->subpackage ][$parent->tutorial_type ];
{ // only add if the parent isn't also a child
$new[$parent->package ][$parent->subpackage ][$parent->tutorial_type ][] = $parent;
// add a new branch to the tree
// process all child tutorials, and insert them in order
// debug("processing parent ".$parent->name);
foreach($parent->ini ['Linked Tutorials'] as $child)
$sub = (empty ($parent->subpackage ) ? '' : $parent->subpackage . '/');
$kid = $parent->package . '/' . $sub . $child . '.' . $parent->tutorial_type;
$_klink = $this->getTutorialLink($kid,false ,false ,array ($parent->package ));
// remove the child from the list of remaining tutorials
foreach($all[$parent->package ][$parent->subpackage ][$parent->tutorial_type ] as $ind => $tute)
if ($klink && $tute->getLink ($this) == $klink)
// set up parent, next and prev links
$tute->setParent ($parent, $this);
// remove the child from the list of tutorials to process
foreach($all[$parent->package ][$parent->subpackage ][$parent->tutorial_type ] as $ind => $t)
if ($t->name == $tute->name )
unset ($all[$parent->package ][$parent->subpackage ][$parent->tutorial_type ][$ind]);
// add to the new ordered list of tutorials
$new[$parent->package ][$parent->subpackage ][$parent->tutorial_type ][] = $tute;
// add all the child's child tutorials to the list
$this->generateTutorialOrder ($tute,$all,$new);
/** Returns the path to this tutorial as a string
* @param parserTutorial $pkg
* @param parserTutorial $subpkg
* @param parserTutorial $namepkg
function _tutorial_path ($pkg, $subpkg = 0 , $namepkg = 0 )
$subpackagename = ($subpkg->subpackage ? '/' . $subpkg->subpackage : '');
return $pkg->package . $subpackagename . '/' . $namepkg->name;
* Creates a tree structure of tutorials
* array('package/subpackage/tutorial1.ext' =>
* array('tutorial' => {@link parserTutorial},
* array('package/subpackage/child1tutorial.ext' => ...,
* 'package/subpackage/child2tutorial.ext' => ...,
* 'package/subpackage/tutorial2.ext' => ...,
* @return array the tutorial tree
function _setupTutorialTree ($parent = false )
if (! isset ($this->processed_tutorials)) {
$this->processed_tutorials = array ();
foreach($this->tutorials as $package => $s)
foreach($s as $subpackage => $t)
foreach($t as $type => $n)
foreach($n as $name => $tutorial)
$child_path = $this->_tutorial_path ($tutorial,$tutorial,$tutorial);
if (isset ($this->processed_tutorials[$child_path])) {
$this->processed_tutorials[$child_path] = $tutorial;
//debug("parent ".$tutorial->name);
$ret = $this->_setupTutorialTree ($tutorial);
$parent_path = $this->_tutorial_path ($parent);
$tree[$parent_path]['tutorial'] = $parent;
// process all child tutorials, and insert them in order
foreach($parent->ini ['Linked Tutorials'] as $child)
if (isset ($this->tutorials[$parent->package ][$parent->subpackage ]
[$parent->tutorial_type ][$child . '.' .
$parent->tutorial_type ])) {
// remove the child from the list of remaining tutorials
$tute = $this->tutorials[$parent->package ][$parent->subpackage ]
[$parent->tutorial_type ][$child . '.' .
$child_path = $this->_tutorial_path ($parent,$parent,$tute);
if (isset ($this->processed_tutorials[$child_path])) {
$this->processed_tutorials[$child_path] = $tute;
if ($tute->name != $child . '.' . $parent->tutorial_type ) {
//echo "Adding [$child_path] to [$parent_path]<br>";
$tree[$parent_path]['child'][$this->_tutorial_path ($parent,$parent,$tute)]['tutorial']
// add all the child's child tutorials to the list
if (!isset ($tree[$parent_path]['child'])) {
$tree[$parent_path]['child'] = $this->_setupTutorialTree ($tute);
$tree[$parent_path]['child'] = array_merge($tree[$parent_path]['child'],
$this->_setupTutorialTree ($tute));
* Debugging function for dumping {@link $tutorial_tree}
if (phpDocumentor_get_class($tree) == 'parsertutorial') return $tree->name. ' extends '. ($tree->parent? $tree->parent ->name : 'nothing');
foreach($tree as $ind => $stuff)
$a .= $indent. '['. $ind. " => \n ". $indent. $x. "]\n";
function sort_package_elements ($a,$b)
if (($a->type == $b->type ) && (isset ($a->isConstructor ) && $a->isConstructor )) return -1;
if (($a->type == $b->type ) && (isset ($b->isConstructor ) && $b->isConstructor )) return 1;
if ($a->type == $b->type ) return strnatcasecmp($a->name ,$b->name );
if ($a->type == 'class') return -1;
if ($b->type == 'class') return 1;
if ($a->type == 'const') return -1;
if ($b->type == 'const') return 1;
if ($a->type == 'var') return -1;
if ($b->type == 'var') return 1;
if ($a->type == 'page') return -1;
if ($b->type == 'page') return 1;
if ($a->type == 'include') return -1;
if ($b->type == 'include') return 1;
if ($a->type == 'define') return -1;
if ($b->type == 'define') return 1;
if ($a->type == 'global') return -1;
if ($b->type == 'global') return 1;
if ($a->type == 'function') return -1;
if ($b->type == 'function') return 1;
function defpackagesort ($a,$b)
if ($a == $GLOBALS['phpDocumentor_DefaultPackageName']) return -1;
if ($b == $GLOBALS['phpDocumentor_DefaultPackageName']) return 0;
* walk over elements by package rather than page
* This method is designed for converters like the PDF converter that need
* everything passed in alphabetical order by package/subpackage and by
* procedural and then class information
* @see PDFdefaultConverter
uksort($r['page'],'strnatcasecmp');
foreach($r['page'] as $page => $oo)
usort($this->package_elements[$package][$subpackage]['page'][$page],array ($this,'sort_package_elements'));
uksort($r['class'],'strnatcasecmp');
foreach($r['class'] as $page => $oo)
usort($r['class'][$page],array ($this,'sort_package_elements'));
foreach($s as $subpackage => $r)
foreach($r['page'] as $page => $elements)
foreach($elements as $element)
if ($element->type == 'page')
$this->curfile = $element->parent ->getFile ();
$this->curname = $this->getPageName ($element->parent );
$this->curpath = $element->parent ->getPath ();
// force all contained elements to have parent package/subpackage
$element->docblock ->package = $this->package;
$element->docblock ->subpackage = $this->subpackage;
$a = $element->docblock ->getKeyword ('access');
foreach($r['class'] as $class => $elements)
foreach($elements as $element)
if ($element->type == 'class')
$this->class = $element->getName ();
$this->killclass = false;
if ($this->checkKillClass ($element->getName (),$element->getPath ())) continue;
$a = $element->docblock ->getKeyword ('access');
if ($this->killclass) continue;
// force all contained elements to have parent package/subpackage
$element->docblock ->package = $this->package;
$element->docblock ->subpackage = $this->subpackage;
if ($this->killclass) continue;
} // if isset($r['class'])
} // foreach($this->package_elements)
* Convert the phpDocumentor parsing/conversion error log
* Convert the list of all @todo tags
* Sorts the @todo list - do not override or modify this function
* @uses _sortTodos passed to {@link usort()} to sort the todo list
foreach($this->todoList as $package => $r) {
usort($this->todoList[$package], array ('Converter', '_sortTodoPackage'));
foreach ($r as $a => $sub) {
usort($this->todoList[$package][$a][1 ],array ('Converter', '_sortTodos'));
function _sortTodoPackage ($a, $b)
function _sortTodos ($a, $b)
* Sorts all indexes - do not override or modify this function
* @uses $leftindex based on the value of leftindex, sorts link arrays
* @uses $class_elements sorts with {@link compareLink}
* @uses $page_elements sorts with {@link compareLink}
* @uses $define_elements sorts with {@link compareLink}
* @uses $global_elements sorts with {@link compareLink}
* @uses $function_elements sorts with {@link compareLink}
* @uses $elements sorts with {@link elementCmp}
* @uses $pkg_elements sorts with {@link elementCmp} after sorting by
* package/subpackage alphabetically
foreach($o1 as $subpackage => $links)
foreach($o1 as $subpackage => $links)
foreach($o1 as $subpackage => $links)
foreach($o1 as $subpackage => $links)
foreach($o1 as $subpackage => $links)
foreach($this->elements as $letter => $nothuing)
foreach($this->pkg_elements[$package] as $subpackage => $els)
if (empty ($els)) continue;
foreach($els as $letter => $yuh)
usort($this->pkg_elements[$package][$subpackage][$letter],array ($this,"elementCmp"));
* sorts {@link $page_contents} by element type as well as alphabetically
* @see $sort_page_contents_by_element_type
if (empty ($els)) continue;
foreach($this->page_contents[$package][$subpackage] as $path => $stuff)
if (!count($pages[$path]->elements )) continue;
usort($pages[$path]->elements ,array ($this,'eltypecmp'));
if (isset ($this->page_contents[$package][$subpackage][$path][0 ]))
* @see Converter::sortIndexes()
function compareLink ($a, $b)
* @see Converter::sortPageContentsByElementType()
function eltypecmp ($a, $b)
if ($a->type == 'page') return -1;
if ($b->type == 'page') return 1;
* does a nat case sort on the specified second level value of the array
function elementCmp ($a, $b)
* Used to stop conversion of @ignored or private @access classes
* @uses $killclass sets killclass based on the value of {@link Classes::$killclass}
* and {@link $package_output}
function checkKillClass ($class, $path)
$this->killclass = false;
if (isset ($this->classes->killclass [$class]) && isset ($this->classes->killclass [$class][$path])) $this->killclass = true;
$a = $this->classes->getClass ($class, $path);
if (PHPDOCUMENTOR_DEBUG && $this->killclass) debug(" $class $path killed" );
* @param abstractLink descendant of abstractLink
* @param array|parserTaglist of @todos|@todo tag
function addTodoLink ($link, $todos)
$this->todoList[$link->package ][] = array ($link, $todos);
* Adds all elements to the {@link $elements, $pkg_elements, $links},
* {@link $linkswithfile} and left indexes - Do not modify or override
* @param parserBase any documentable element descendant of parserBase
* @param false|parserPageonly used to add a {@link parserPage} if the
* $element passed is a parserPage
* @staticvar string path of current page, used for {@link $page_contents} setup
function addElement (&$element,$pageel=false )
if ($this->package_output )
if (!in_array ($this->package , $this->package_output )) return;
if ($pageel && phpDocumentor_get_class ($pageel) == 'parserdata')
if (isset ($pageel->docblock ) && phpDocumentor_get_class ($pageel->docblock ) == 'parserdocblock')
$a = $pageel->docblock ->getKeyword ('todo');
if ($a && !empty ($a->value [0 ]))
$this->addTodoLink ($this->addLink ($element),$a);
if (isset ($element->docblock ))
$a = $element->docblock ->getKeyword ('access');
$a = $element->docblock ->getKeyword ('todo');
if ($a && !empty ($a->value [0 ]))
if ($element->type != 'include') {
$this->addTodoLink ($this->addLink ($element),$a);
$startPositionOfElementName = 0; // which character of the element name actually starts its textual name
$link = $this->addLink ($element);
$curpath = $element->getPath ();
$link = $this->addLink ($element);
$link = $this->addLink ($element);
$link = $this->addLink ($element);
$link = $this->addLink ($element);
$startPositionOfElementName = 1; // lose the leading "$" character
$link = $this->addLink ($element);
$startPositionOfElementName = 1; // lose the leading "$" character
$link = $this->addLink ($element);
$link = $this->addLink ($element);
$link = $this->addLink ($element);
if ($element->getType () != 'include')
if ($element->getType () == 'var' || $element->getType () == 'method'|| $element->getType () == 'const')
$this->links [$this->package][$this->subpackage][$element->getType ()][$element->class][$element->getName ()] = $link;
$this->linkswithfile [$this->package][$this->subpackage][$element->getType ()][$element->getPath ()][$element->class][$element->getName ()] = $link;
if ($element->type == 'page')
$this->links [$this->package][$this->subpackage][$element->getType ()][$element->getFile ()] = $link;
$this->linkswithfile [$this->package][$this->subpackage][$element->getType ()][$element->getPath ()][$element->getFile ()] = $link;
$this->links [$this->package][$this->subpackage][$element->getType ()][$element->getName ()] = $link;
$this->linkswithfile [$this->package][$this->subpackage][$element->getType ()][$element->getPath ()][$element->getName ()] = $link;
if ($element->type == 'page')
* returns an abstract link to element. Do not modify or override
* This method should only be called in process of Conversion, unless
* $element is a parserPage, or $page is set to true, and $element is
* @return abstractLink abstractLink descendant
* @param parserElement element to add a new link (descended from
* {@link abstractLink})to the {@link $links} array
* @param string classname for elements that are class-based (this may be
* deprecated in the future, as the classname
* should be contained within the element. if $element is a
* page, this parameter is a package name
* @param string subpackage name for page elements
function addLink (&$element,$page = false )
// create a fake parserPage to extract the fileAlias for this link
$fakepage->setPath ($element->getPath ());
$fakepage->setFile (basename($element->getPath ()));
$this->curname = $this->getPageName ($fakepage);
$x->addLink ($element->getPath (), $this->curname , $element->name , $element->docblock ->package, $element->docblock ->subpackage, $element->docblock ->category );
$x->addLink ($element->getPath (), $this->curname , $element->name , $element->docblock ->package, $element->docblock ->subpackage, $element->docblock ->category );
$x->addLink ($element->getPath (), $this->curname , $element->name , $element->docblock ->package, $element->docblock ->subpackage, $element->docblock ->category );
$x->addLink ($element->getPath (), $this->curname , $element->name , $element->docblock ->package, $element->docblock ->subpackage, $element->docblock ->category );
$x->addLink ($this->class, $element->getPath (), $this->curname , $element->name , $element->docblock ->package, $element->docblock ->subpackage, $element->docblock ->category );
$x->addLink ($this->class, $element->getPath (), $this->curname , $element->name , $element->docblock ->package, $element->docblock ->subpackage, $element->docblock ->category );
$x->addLink ($this->class, $element->getPath (), $this->curname , $element->name , $element->docblock ->package, $element->docblock ->subpackage, $element->docblock ->category );
$x->addLink ($element->getPath (),$this->getPageName ($element),$element->file,$element->package, $element->subpackage, $element->category );
* Return a tree of all classes that extend this class
* The data structure returned is designed for a non-recursive algorithm,
* and is somewhat complex.
* In most cases, the array returned is:
* array('link' => {@link classLink} to $class,
* 'children' => array(array('class' => 'childclass1',
* 'package' => 'child1package'),
* array('class' => 'childclass2',
* 'package' => 'child2package'),...
* 'child1package#childclass1' =>
* array('link' => {@link classLink} to childclass1,
* 'children' => array(array('class' => 'kidclass',
* 'package' => 'kidpackage'),...
* 'kidpackage#kidclass' =>
* array('link' => {@link classLink} to kidclass,
* 'parent' => 'child1package#childclass1',
* 'children' => array() // no children
* To describe this format using language, every class in the tree has an
* entry in the first level of the array. The index for all child
* classes that extend the root class is childpackage#childclassname.
* Each entry in the array has 3 elements: link, parent, and children.
* <li>link - a {@link classLink} to the current class</li>
* <li>parent - a {@link classLink} to the class's parent, or false (except for one special case described below)</li>
* <li>children - an array of arrays, each entry has a 'class' and 'package' index to the child class,
* used to find the entry in the big array</li>
* special cases are when the #root class has a parent in another package,
* or when the #root class extends a class not found
* by phpDocumentor. In the first case, parent will be a
* classLink to the parent class. In the second, parent will be the
* in this case, the #root entry will be array('link' => classLink to X, 'parent' => 'Y', children => array(...))
* The fastest way to design a method to process the array returned
* is to copy HTMLframesConverter::getRootTree() into
* your converter and to modify the html to whatever output format you are going to use
* @see HTMLframesConverter::getRootTree()
* @param string class name
* @return array Format: see docs
$root = $this->classes->getClassByPackage ($class,$package);
if (!$root) return false;
$class_children = $this->classes->getDefiniteChildren ($class,$root->curfile);
// special case: parent class is found, but is not part of this package, class has no children
$x = $root->getParent ($this);
if ($x->docblock ->package != $package)
return array ('#root' => array ('link' => $v,'parent' => Converter::getClassLink($x->getName (),$x->docblock ->package,$x->getPath ()), 'children' => array ()));
{ // class has normal situation, no children
return array ('#root' => array ('link' => Converter::getClassLink($root->getName (),$package,$root->getPath ()), 'parent' => $root->getExtends (),'children' => array ()));
return array ('#root' => array ('link' => Converter::getClassLink($root->getName (),$package,$root->getPath ()), 'parent' => false , 'children' => array ()));
// special case: parent class is found, but is not part of this package, class has children
$x = $root->getParent ($this);
if ($x->docblock ->package != $package)
$my_tree = array ('#root' => array ('link' => $v, 'parent' => Converter::getClassLink($x->getName (),$x->docblock ->package,$x->getPath ()), 'children' => array ()));
$my_tree = array ('#root' => array ('link' => Converter::getClassLink($root->getName (),$package,$root->getPath ()), 'parent' => false , 'children' => array ()));
// location of tree walker
$lastcur = array (array (false ,0 ));
if (isset ($class_children))
if (isset ($my_tree[$cur]['children'][$childpos + 1 ]))
$cur = $my_tree[$cur]['children'][$childpos + 1 ];
$x = $this->classes->getClassByPackage ($cur['class'],$cur['package']);
$cur = $cur['package'] . '#' . $cur['class'];
$my_tree[$cur]['parent'] = $par;
$my_tree[$cur]['children'] = array ();
$class_children = $this->classes->getDefiniteChildren ($x->getName (), $x->curfile);
foreach($class_children as $chileclass => $chilefile)
$ch = $this->classes->getClass ($chileclass,$chilefile);
$my_tree[$cur]['children'][] = array ('class' => $ch->getName (), 'package' => $ch->docblock ->package);
usort($my_tree[$cur]['children'],'rootcmp');
if (isset ($my_tree[$cur]['children'][$childpos]))
$cur = $my_tree[$cur]['children'][$childpos];
$x = $this->classes->getClassByPackage ($cur['class'],$cur['package']);
$cur = $cur['package'] . '#' . $cur['class'];
$my_tree[$cur]['parent'] = $par;
$my_tree[$cur]['children'] = array ();
$class_children = $this->classes->getDefiniteChildren ($x->getName (), $x->curfile);
* @return bool true if a link to this class exists in package $package and subpackage $subpackage
* @param string $expr class name
* @param string $package package to search in
* @param string $subpackage subpackage to search in
function isLinkedClass ($expr,$package,$subpackage,$file=false )
return isset ($this->linkswithfile [$package][$subpackage]['class'][$file][$expr]);
return isset ($this->links [$package][$subpackage]['class'][$expr]);
* @return bool true if a link to this function exists in package $package and subpackage $subpackage
* @param string $expr function name
* @param string $package package to search in
* @param string $subpackage subpackage to search in
function isLinkedFunction ($expr,$package,$subpackage,$file=false )
return isset ($this->linkswithfile [$package][$subpackage]['function'][$file][$expr]);
return isset ($this->links [$package][$subpackage]['function'][$expr]);
* @return bool true if a link to this define exists in package $package and subpackage $subpackage
* @param string $expr define name
* @param string $package package to search in
* @param string $subpackage subpackage to search in
function isLinkedDefine ($expr,$package,$subpackage,$file=false )
return isset ($this->linkswithfile [$package][$subpackage]['define'][$file][$expr]);
return isset ($this->links [$package][$subpackage]['define'][$expr]);
* @return bool true if a link to this define exists in package $package and subpackage $subpackage
* @param string $expr define name
* @param string $package package to search in
* @param string $subpackage subpackage to search in
function isLinkedGlobal ($expr,$package,$subpackage,$file=false )
return isset ($this->linkswithfile [$package][$subpackage]['global'][$file][$expr]);
return isset ($this->links [$package][$subpackage]['global'][$expr]);
* @return bool true if a link to this procedural page exists in package $package and subpackage $subpackage
* @param string $expr procedural page name
* @param string $package package to search in
* @param string $subpackage subpackage to search in
function isLinkedPage ($expr,$package,$subpackage,$path=false )
return isset ($this->linkswithfile [$package][$subpackage]['page'][$path][$expr]);
return isset ($this->links [$package][$subpackage]['page'][$expr]);
* @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class
* @param string $expr method name
* @param string $class class name
* @param string $package package to search in
* @param string $subpackage subpackage to search in
function isLinkedMethod ($expr,$package,$subpackage,$class,$file=false )
return isset ($this->linkswithfile [$package][$subpackage]['method'][$file][$class][$expr]);
return isset ($this->links [$package][$subpackage]['method'][$class][$expr]);
* @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class
* @param string $expr var name
* @param string $class class name
* @param string $package package to search in
* @param string $subpackage subpackage to search in
function isLinkedVar ($expr,$package,$subpackage,$class,$file=false )
return isset ($this->linkswithfile [$package][$subpackage]['var'][$file][$class][$expr]);
return isset ($this->links [$package][$subpackage]['var'][$class][$expr]);
* @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class
* @param string $expr constant name
* @param string $class class name
* @param string $package package to search in
* @param string $subpackage subpackage to search in
function isLinkedConst ($expr,$package,$subpackage,$class,$file=false )
return isset ($this->linkswithfile [$package][$subpackage]['const'][$file][$class][$expr]);
return isset ($this->links [$package][$subpackage]['const'][$class][$expr]);
* return false or a {@link classLink} to $expr
* @param string $expr class name
* @param string $package package name
* @return mixed returns a {@link classLink} or false if the element is not found in package $package
function getClassLink($expr,$package,$file=false , $text = false )
if (!isset ($this->links [$package])) return false;
foreach($this->links [$package] as $subpackage => $notused)
if ($this->isLinkedClass ($expr,$package,$subpackage,$file))
return $this->linkswithfile [$package][$subpackage]['class'][$file][$expr];
return $this->links [$package][$subpackage]['class'][$expr];
* return false or a {@link functionLink} to $expr
* @param string $expr function name
* @param string $package package name
* @return mixed returns a {@link functionLink} or false if the element is not found in package $package
if (!isset ($this->links [$package])) return false;
foreach($this->links [$package] as $subpackage => $notused)
if ($this->isLinkedFunction ($expr,$package,$subpackage,$file))
return $this->linkswithfile [$package][$subpackage]['function'][$file][$expr];
return $this->links [$package][$subpackage]['function'][$expr];
* return false or a {@link defineLink} to $expr
* @param string $expr constant name
* @param string $package package name
* @return mixed returns a {@link defineLink} or false if the element is not found in package $package
function getDefineLink($expr,$package,$file=false , $text = false )
if (!isset ($this->links [$package])) return false;
foreach($this->links [$package] as $subpackage => $notused)
if ($this->isLinkedDefine ($expr,$package,$subpackage,$file))
return $this->linkswithfile [$package][$subpackage]['define'][$file][$expr];
return $this->links [$package][$subpackage]['define'][$expr];
* return false or a {@link globalLink} to $expr
* @param string $expr global variable name (with leading $)
* @param string $package package name
* @return mixed returns a {@link defineLink} or false if the element is not found in package $package
function getGlobalLink($expr,$package,$file=false , $text = false )
if (!isset ($this->links [$package])) return false;
foreach($this->links [$package] as $subpackage => $notused)
if ($this->isLinkedGlobal ($expr,$package,$subpackage,$file))
return $this->linkswithfile [$package][$subpackage]['global'][$file][$expr];
return $this->links [$package][$subpackage]['global'][$expr];
* return false or a {@link pageLink} to $expr
* @param string $expr procedural page name
* @param string $package package name
* @return mixed returns a {@link pageLink} or false if the element is not found in package $package
function getPageLink($expr,$package,$path = false , $text = false , $packages = false )
if (!isset ($this->links [$package])) return false;
foreach($this->links [$package] as $subpackage => $notused)
if ($this->isLinkedPage ($expr,$package,$subpackage,$path))
return $this->linkswithfile [$package][$subpackage]['page'][$path][$expr];
return $this->links [$package][$subpackage]['page'][$expr];
* return false or a {@link methodLink} to $expr in $class
* @param string $expr method name
* @param string $class class name
* @param string $package package name
* @return mixed returns a {@link methodLink} or false if the element is not found in package $package, class $class
function getMethodLink($expr,$class,$package,$file=false , $text = false )
if (!isset ($this->links [$package])) return false;
foreach($this->links [$package] as $subpackage => $notused)
if ($this->isLinkedMethod ($expr,$package,$subpackage,$class,$file))
return $this->linkswithfile [$package][$subpackage]['method'][$file][$class][$expr];
return $this->links [$package][$subpackage]['method'][$class][$expr];
* return false or a {@link varLink} to $expr in $class
* @param string $expr var name
* @param string $class class name
* @param string $package package name
* @return mixed returns a {@link varLink} or false if the element is not found in package $package, class $class
function getVarLink($expr,$class,$package,$file=false , $text = false )
if (!isset ($this->links [$package])) return false;
foreach($this->links [$package] as $subpackage => $notused)
if ($this->isLinkedVar ($expr,$package,$subpackage,$class,$file))
return $this->linkswithfile [$package][$subpackage]['var'][$file][$class][$expr];
return $this->links [$package][$subpackage]['var'][$class][$expr];
* return false or a {@link constLink} to $expr in $class
* @param string $expr constant name
* @param string $class class name
* @param string $package package name
* @return mixed returns a {@link varLink} or false if the element is not found in package $package, class $class
function getConstLink($expr,$class,$package,$file=false , $text = false )
if (!isset ($this->links [$package])) return false;
foreach($this->links [$package] as $subpackage => $notused)
if ($this->isLinkedConst ($expr,$package,$subpackage,$class,$file))
return $this->linkswithfile [$package][$subpackage]['const'][$file][$class][$expr];
return $this->links [$package][$subpackage]['const'][$class][$expr];
* The meat of the @tutorial tag and inline {@}tutorial} tag
* Take a string and return an abstract link to the tutorial it represents.
* Since tutorial naming literally works like the underlying filesystem, the
* way to reference the tutorial is similar. Tutorials are located in a
* subdirectory of any directory parsed, which is named 'tutorials/' (we
* try to make things simple when we can :). They are further organized by
* package and subpackage as:
* tutorials/package/subpackage
* and the files are named *.cls, *.pkg, or *.proc, and so a link to a tutorial
* named file.cls can be referenced (depending on context) as any of:
* * @tutorial package/subpackage/file.cls
* * @tutorial package/file.cls
* The first case will only be needed if file.cls exists in both the current
* package, in anotherpackage/file.cls and in anotherpackage/subpackage/file.cls
* and you wish to reference the one in anotherpackage/subpackage.
* The second case is only needed if you wish to reference file.cls in another
* package and it is unique in that package. the third will link to the first
* file.cls it finds using this search method:
* <li>current package/subpackage</li>
* <li>all other subpackages of current package</li>
* <li>parent package, if this package has classes that extend classes in
* <li>all other packages</li>
* @return tutorialLink|stringreturns either a link, or the original text, if not found
* @param string the original expression
* @param string package to look in first
* @param string subpackage to look in first
* @param array array of package names to search in if not found in parent packages.
* This is used to limit the search, phpDocumentor automatically searches
function getTutorialLink($expr, $package = false , $subpackage = false , $packages = false )
// is $expr a comma-delimited list?
for($i=0; $i< count($a); $i++ )
// if so return each component with a link
if (!$package) $package = $this->package;
if (!$subpackage) $subpackage = $this->subpackage;
elseif (isset ($packages[$package])) unset ($packages[$package]);
$ext = pathinfo($expr, PATHINFO_EXTENSION );
if (isset ($this->tutorials [$package][$subpackage][$ext][$expr]))
$a = $this->tutorials [$package][$subpackage][$ext][$expr];
$link->addLink ($subsection,$a->path,$a->name ,$a->package,$a->subpackage,$a->getTitle ($this,$subsection));
if (isset ($packages[$package])) unset ($packages[$package]);
if (isset ($this->tutorials [$package]))
if (isset ($this->tutorials [$package][$subpackage][$ext][$expr]))
$a = $this->tutorials [$package][$subpackage][$ext][$expr];
foreach($this->tutorials [$package] as $subpackage => $stuff)
if (isset ($stuff[$ext][$expr]))
$a = $stuff[$ext][$expr];
// look in parent package first, if found
// no parent package, so start with the first one that's left
list ($package,) = @each($packages);
if (isset ($packages[$package])) unset ($packages[$package]);
} while (count($packages) || $package);
* The meat of the @see tag and inline {@}link} tag
* $expr is a string with many allowable formats:
* <li>proceduralpagename.ext</li>
* <li>classname::function()</li>
* <li>classname::constantname</li> (new 1.2.4)
* <li>classname::$variablename</li>
* <li>object classname</li>
* <li>function functionname()</li>
* <li>global $globalvarname</li>
* <li>packagename#expr where expr is any of the above</li>
* New in version 1.1, you can explicitly specify a package to link to that
* is different from the current package. Use the # operator
* to specify a new package, as in tests#bug-540368.php (which should appear
* as a link like: "{@link tests#bug-540368.php}"). This
* example links to the procedural page bug-540368.php in package
* tests. Also, the "function" operator is now used to specifically
* link to a function instead of a method in the current class.
* // from inside the class definition, use "function conflict()" to refer to procedural function "conflict()"
* If classname:: is not present, and the see tag is in a documentation
* block within a class, then the function uses the classname to
* search for $expr as a function or variable within classname, or any of its parent classes.
* given an $expr without '$', '::' or '()' getLink first searches for
* classes, procedural pages, constants, global variables, and then searches for
* methods and variables within the default class, and finally for any function
* @param string $expr expression to search for a link
* @param string $package package to start searching in
* @param array $packages list of all packages to search in
* @return mixed getLink returns a descendant of {@link abstractLink} if it finds a link, otherwise it returns a string
* @see getPageLink(), getDefineLink(), getVarLink(), getFunctionLink(), getClassLink()
* @see pageLink, functionLink, defineLink, classLink, methodLink, varLink
function &getLink($expr, $package = false , $packages = false )
// is $expr a comma-delimited list?
for($i=0; $i< count($a); $i++ )
// if so return each component with a link
{ // can have exactly 1 package override, otherwise it's ignored
// feature 564991, link to php manual
if ($a[0 ] == 'PHP_MANUAL') {
$s = 'http://www.php.net/'. $a[1 ];
$a = &$this->_getLink ($expr, $package, $packages);
function &_getLink ($expr, $package = false , $packages = false )
if (!$package) $package = $this->package;
elseif (isset ($packages[$package])) unset ($packages[$package]);
if (strpos($expr,'function ') === 0 )
{ // asking for a function, not a method
if (strpos($expr,'global ') === 0 )
{ // asking for a global variable
if (strpos($expr,'object ') === 0 )
if (strpos($expr,'constant ') === 0 )
// is $expr simply a word? see if it is the class
if (trim($expr) == $class)
// if not, check to see if it is a method or variable of this class tree
// if get is neither get() nor $get, assume get is a function, add () to make get()
if (strpos($expr,'$') !== 0 && !strpos($expr,'()')) //$get = $get.'()';
if ($a = $this->getLinkMethod ($expr,$class,$package)) return $a;
if ($a = $this->getLinkConst ($expr,$class,$package)) return $a;
if ($a = $this->getLinkVar ('$'. $expr,$class,$package)) return $a;
if (strpos($expr,'()')) if ($a = $this->getLinkMethod ($expr,$class,$package)) return $a;
if (is_numeric(strpos($expr,'$'))) if ($a = $this->getLinkVar ($expr,$class,$package)) return $a;
// if (strpos($expr,'.'))
if (isset ($packages[$package])) unset ($packages[$package]);
// is $expr in class::method() or class::$variable format?
if (strpos($expr,'function ') === 0 )
{ // asking for a function, not a method
$test = $this->_getDoubleColon ($expr, $package, $packages, $class, $links);
if (strpos($test, 'parent::') === 0 ) return $test;
// $expr does not have ::
// default to current class, whose name is contained in $this->render->parent
// $expr is a function? (non-method)
// otherwise, see if it is a method
// extract the function name, use it to retrieve the file that the function is in
// $page = $this->func_page[str_replace('function ','',str_replace('()','',$expr))];
// $expr is just a word. First, test to see if it is a function of the current package
// look in parent package first, if found
if (isset ($packages[$package])) unset ($packages[$package]);
// no parent package, so start with the first one that's left
if ($package && isset ($packages[$package]))
unset ($packages[$package]);
} while (count($packages) || $package);
// feature 564991, link to php manual
$return = 'http://www.php.net/'. str_replace(array ('(',')'),array ('',''),$expr);
* Split up getLink to make it easier to debug
function _getDoubleColon (&$expr, &$package, &$packages, $class, $links)
$class_method = explode('::',$expr);
if ($class_method[0 ] == 'parent')
// can only have parent in the same package as the class! subtle bug
$cl = $this->classes->getClassByPackage ($class,$package);
{ // this is possible if an example file has parent::method()
$par = $cl->getParent ($this);
$package = $par->docblock ->package;
$phpparent = $par->getName ();
if ($phpparent) $class_method[0 ] = $phpparent;
if (strpos($class_method[1 ],'()'))
// strip everything but the function name, return a link
* cycle through parent classes to retrieve a link to a method
* do not use or override, used by getLink
function &getLinkMethod ($expr, $class, $package)
// is $expr in class::method() or class::$variable format?
$class_method = explode('::',$expr);
if ($class_method[0 ] == 'parent')
$cl = $this->classes->getClassByPackage ($class,$package);
$par = $cl->getParent ($this);
$package = $par->docblock ->package;
$phpparent = $par->getName ();
} else addWarning(PDERROR_CLASSPARENT_NOTFOUND ,$class,$package,$class_method[1 ]);
if ($phpparent) $class_method[0 ] = $phpparent;
$cl = $this->classes->getClassByPackage ($class,$package);
if (strpos($class_method[1 ],'()'))
// strip everything but the function name, return a link
$cl = $this->classes->getClassByPackage ($class,$package);
$par = $cl->getParent ($this);
$package = $par->docblock ->package;
$class = $par->getName ();
* cycle through parent classes to retrieve a link to a var
* do not use or override, used by getLink
function &getLinkVar ($expr, $class, $package)
// is $expr in class::method() or class::$variable format?
$class_method = explode('::',$expr);
if ($class_method[0 ] == 'parent')
$cl = $this->classes->getClassByPackage ($class,$package);
$par = $cl->getParent ($this);
$package = $par->docblock ->package;
$phpparent = $par->getName ();
} else addWarning(PDERROR_CLASSPARENT_NOTFOUND ,$class,$package,$class_method[1 ]);
if ($phpparent) $class_method[0 ] = $phpparent;
$cl = $this->classes->getClassByPackage ($class,$package);
if ($test = Converter::getVarLink('$'. $class_method[1 ], $class_method[0 ], $package)) return $test;
$cl = $this->classes->getClassByPackage ($class,$package);
$par = $cl->getParent ($this);
$package = $par->docblock ->package;
$class = $par->getName ();
* cycle through parent classes to retrieve a link to a class constant
* do not use or override, used by getLink
function &getLinkConst ($expr, $class, $package)
// is $expr in class::method() or class::$variable format?
$class_method = explode('::',$expr);
if ($class_method[0 ] == 'parent')
$cl = $this->classes->getClassByPackage ($class,$package);
$par = $cl->getParent ($this);
$package = $par->docblock ->package;
$phpparent = $par->getName ();
} else addWarning(PDERROR_CLASSPARENT_NOTFOUND ,$class,$package,$class_method[1 ]);
if ($phpparent) $class_method[0 ] = $phpparent;
$cl = $this->classes->getClassByPackage ($class,$package);
$cl = $this->classes->getClassByPackage ($class,$package);
$par = $cl->getParent ($this);
$package = $par->docblock ->package;
$class = $par->getName ();
* take URL $link and text $text and return a link in the format needed for the Converter
* @param string text to display
* @return string link to $link
* take {@link abstractLink} descendant and text $eltext and return a link
* in the format needed for the Converter
* @return string link to $element
* take {@link abstractLink} descendant and text $eltext and return a
* unique ID in the format needed for the Converter
* @return string unique identifier of $element
* Convert README/INSTALL/CHANGELOG file contents to output format
* @param README|INSTALL|CHANGELOG
* @param string contents of the file
* Convert all elements to output format
* This will call ConvertXxx where Xxx is {@link ucfirst}($element->type).
* It is expected that a child converter defines a handler for every
* element type, even if that handler does nothing. phpDocumentor will
* terminate with an error if a handler doesn't exist.
* Since 1.2.0 beta 3, this function has been moved from child converters
* to the parent, because it doesn't really make sense to put it in the
* child converter, and we can add error handling.
* @throws {@link PDERROR_NO_CONVERT_HANDLER}
* @param mixed {@link parserElement} descendant or {@link parserPackagePage} or {@link parserData}
$handler = 'convert'. ucfirst($element->type );
$this->$handler($element);
* All of the convert* handlers set up template variables for the Smarty
* template.{@internal In addition, the {@link newSmarty()} method is
* called to retrieve the global Smarty template}}
* Default Tutorial Handler
* Sets up the tutorial template, and its prev/next/parent links
* Retrieves the title using {@link parserTutorial::getTitle()} and uses the
* {@link parserTutorial::prev, parserTutorial::next, parserTutorial::parent}
* links to set up those links.}}}
$template->assign ('contents',$x);
$template->assign ('title',$element->getTitle ($this));
$template->assign ('nav',$element->parent || $element->prev || $element->next);
$template->assign ('up',$this->getId($element->parent ));
$template->assign ('uptitle',$element->parent ->title);
$template->assign ('prev',$this->getId($element->prev));
$template->assign ('prevtitle',$element->prev->title);
$template->assign ('next',$this->getId($element->next));
$template->assign ('nexttitle',$element->next->title);
* Sets up the class template.
* {@internal special methods
* {@link generateChildClassList(), generateFormattedClassTree()},
* {@link getFormattedConflicts, getFormattedInheritedMethods},
* and {@link getFormattedInheritedVars} are called to complete vital
$this->class = $element->getName ();
$this->class_data->assign ("class_name",$element->getName ());
$this->class_data->assign ("is_interface", $element->isInterface ());
$this->class_data->assign ("line_number",$element->getLineNumber ());
$this->class_data->assign ("source_location",$element->getSourceLocation ($this));
$this->class_data->assign ("sdesc",$docblock['sdesc']);
$this->class_data->assign ("desc",$docblock['desc']);
$this->class_data->assign ("access", $docblock['access']);
$this->class_data->assign ("abstract", $docblock['abstract']);
$this->class_data->assign ("tags",$docblock['tags']);
$this->class_data->assign ("api_tags",$docblock['api_tags']);
$this->class_data->assign ("info_tags",$docblock['info_tags']);
$this->class_data->assign ("utags",$docblock['utags']);
$this->class_data->assign ( "prop_tags", $docblock['property_tags'] );
$this->class_data->assign ("class_slink",$this->getSourceAnchor ($element->getPath (),$element->getLineNumber (),$element->getLineNumber (),true ));
if (!empty ($inherited_methods))
$this->class_data->assign ("imethods",$inherited_methods);
if (!empty ($inherited_vars))
$this->class_data->assign ("ivars",$inherited_vars);
if (!empty ($inherited_consts))
$this->class_data->assign ("iconsts",$inherited_consts);
* Converts method for template output
* This function must be called by a child converter with any extra
* template variables needed in the parameter $addition
$fname = $element->getName ();
if ($element->isConstructor ) $returntype = $element->class;
if ($element->docblock ->return )
$a = $element->docblock ->return ->Convert($this);
$returntype = $element->docblock ->return ->converted_returnType;
$params = $param_i = array ();
if (count($element->docblock ->params ))
foreach($element->docblock ->params as $param => $val)
$params[] = $param_i[$param] = array ("var" => $param,"datatype" => $val->converted_returnType ,"data" => $a);
if ($element->docblock ->hasaccess ) {
$acc = $docblock['access'];
$additions["slink"] = $this->getSourceAnchor ($element->getPath (),$element->getLineNumber (),$element->getLineNumber (),true );
'sdesc' => $docblock['sdesc'],
'desc' => $docblock['desc'],
'static' => $docblock['static'],
'abstract' => $docblock['abstract'],
'tags' => $docblock['tags'],
'api_tags' => $docblock['api_tags'],
'see_tags' => $docblock['see_tags'],
'info_tags_sorted' => $docblock['info_tags_sorted'],
'info_tags' => $docblock['info_tags'],
'utags' => $docblock['utags'],
'constructor' => $element->isConstructor ,
'function_name' => $fname,
'function_return' => $returntype,
'function_call' => $element->getFunctionCall (),
'ifunction_call' => $element->getIntricateFunctionCall ($this, $param_i),
'line_number' => $element->getLineNumber (),
'id' => $this->getId($element),
* Converts class variables for template output.
* This function must be called by a child converter with any extra
* template variables needed in the parameter $addition
function convertVar(&$element, $additions = array ())
if ($element->docblock ->hasaccess )
$acc = $element->docblock ->tags ['access'][0 ]->value;
if ($element->docblock ->var )
$b = $element->docblock ->var ->converted_returnType;
$additions["slink"] = $this->getSourceAnchor ($element->getPath (),$element->getLineNumber (),$element->getLineNumber (),true );
'sdesc' => $docblock['sdesc'],
'desc' => $docblock['desc'],
'static' => $docblock['static'],
'abstract' => $docblock['abstract'],
'utags' => $docblock['utags'],
'tags' => $docblock['tags'],
'api_tags' => $docblock['api_tags'],
'info_tags' => $docblock['info_tags'],
'var_name' => $element->getName (),
'has_default' => strlen($element->getValue ()),
'var_default' => $this->postProcess($element->getValue ()),
'line_number' => $element->getLineNumber (),
'id' => $this->getId($element)
* Converts class constants for template output.
* This function must be called by a child converter with any extra
* template variables needed in the parameter $addition
if ($element->docblock ->hasaccess )
$acc = $element->docblock ->tags ['access'][0 ]->value;
$additions["slink"] = $this->getSourceAnchor ($element->getPath (),$element->getLineNumber (),$element->getLineNumber (),true );
'sdesc' => $docblock['sdesc'],
'desc' => $docblock['desc'],
'access' => $docblock['access'],
'abstract' => $docblock['abstract'],
'utags' => $docblock['utags'],
'tags' => $docblock['tags'],
'api_tags' => $docblock['api_tags'],
'info_tags' => $docblock['info_tags'],
'const_name' => $element->getName (),
'const_value' => $this->postProcess($element->getValue ()),
'line_number' => $element->getLineNumber (),
'id' => $this->getId($element)
* {@internal In addition to setting up the smarty template with {@link newSmarty()},
* this class uses {@link getSourceLocation()} and {@link getClassesOnPage()}
* to set template variables. Also used is {@link getPageName()}, to get
* a Converter-specific name for the page.}}}
$this->page = $this->getPageName ($element->parent );
$this->path = $element->parent ->getPath ();
$this->curpage = &$element->parent;
$this->page_data->assign ("source_location",$element->parent ->getSourceLocation ($this));
$this->page_data->assign ("functions",array ());
$this->page_data->assign ("includes",array ());
$this->page_data->assign ("hasclasses",$element->hasClasses ());
$this->page_data->assign ("hasinterfaces",$element->hasInterfaces ());
$this->page_data->assign ("name", $element->parent ->getFile ());
if ($t = $element->getTutorial ())
$this->page_data->assign ("sdesc",$docblock['sdesc']);
$this->page_data->assign ("desc",$docblock['desc']);
$this->page_data->assign ("tags",$docblock['tags']);
$this->page_data->assign ("api_tags",$docblock['api_tags']);
$this->page_data->assign ("info_tags",$docblock['info_tags']);
$this->page_data->assign ("utags",$docblock['utags']);
* Converts global variables for template output
* This function must be called by a child converter with any extra
* template variables needed in the parameter $addition
* In addition to using {@link prepareDocBlock()}, this method also
* uses utility functions {@link getGlobalValue(), getFormattedConflicts()}}}}
* @uses postProcess() on global_value template value, makes it displayable
* @param array any additional template variables should be in this array
$addition["slink"] = $this->getSourceAnchor ($element->getPath (),$element->getLineNumber (),$element->getLineNumber (),true );
array ('sdesc' => $docblock['sdesc'],
'desc' => $docblock['desc'],
'tags' => $docblock['tags'],
'api_tags' => $docblock['api_tags'],
'info_tags' => $docblock['info_tags'],
'utags' => $docblock['utags'],
'global_name' => $element->getName (),
'global_type' => $element->getDataType ($this),
'global_value' => $value,
'line_number' => $element->getLineNumber (),
'id' => $this->getId($element)),
* Converts defines for template output
* This function must be called by a child converter with any extra
* template variables needed in the parameter $addition
* In addition to using {@link prepareDocBlock()}, this method also
* uses utility functions {@link getGlobalValue(), getFormattedConflicts()}}}}
* @uses postProcess() on define_value template value, makes it displayable
* @param array any additional template variables should be in this array
$addition["slink"] = $this->getSourceAnchor ($element->getPath (),$element->getLineNumber (),$element->getLineNumber (),true );
array ('sdesc' => $docblock['sdesc'],
'desc' => $docblock['desc'],
'tags' => $docblock['tags'],
'api_tags' => $docblock['api_tags'],
'info_tags' => $docblock['info_tags'],
'utags' => $docblock['utags'],
'define_name' => $element->getName (),
'line_number' => $element->getLineNumber (),
'define_value' => $this->postProcess($element->getValue ()),
'id' => $this->getId($element)),
* Converts includes for template output
* This function must be called by a child converter with any extra
* template variables needed in the parameter $addition
$addition["slink"] = $this->getSourceAnchor ($element->getPath (),$element->getLineNumber (),$element->getLineNumber (),true );
array ('sdesc' => $docblock['sdesc'],
'desc' => $docblock['desc'],
'tags' => $docblock['tags'],
'api_tags' => $docblock['api_tags'],
'info_tags' => $docblock['info_tags'],
'utags' => $docblock['utags'],
'include_name' => $element->getName (),
'line_number' => $element->getLineNumber (),
'include_value' => $per),
* Converts function for template output
* This function must be called by a child converter with any extra
* template variables needed in the parameter $addition
$fname = $element->getName ();
$params = $param_i = array ();
if (count($element->docblock ->params ))
foreach($element->docblock ->params as $param => $val)
$params[] = $param_i[$param] = array ("var" => $param,"datatype" => $val->converted_returnType ,"data" => $a);
if ($element->docblock ->return )
$a = $element->docblock ->return ->Convert($this);
$returntype = $element->docblock ->return ->converted_returnType;
$addition["slink"] = $this->getSourceAnchor ($element->getPath (),$element->getLineNumber (),$element->getLineNumber (),true );
array ('sdesc' => $docblock['sdesc'],
'desc' => $docblock['desc'],
'tags' => $docblock['tags'],
'api_tags' => $docblock['api_tags'],
'info_tags' => $docblock['info_tags'],
'utags' => $docblock['utags'],
'function_name' => $fname,
'function_return' => $returntype,
'ifunction_call' => $element->getIntricateFunctionCall ($this, $param_i),
'function_call' => $element->getFunctionCall (),
'line_number' => $element->getLineNumber (),
'id' => $this->getId($element),
* convert the element's DocBlock for output
* This function converts all tags and descriptions for output
* @param mixed any descendant of {@link parserElement}, or {@link parserData}
* @param array used to translate tagnames into other tags
* @param boolean set to false for pages and classes, the only elements allowed to specify @package
* array('sdesc' => DocBlock summary
* 'desc' => DocBlock detailed description
* 'tags' => array('keyword' => tagname, 'data' => tag description)
* 'api_tags' => array('keyword' => tagname, 'data' => tag description)
* known api documentation tags
* 'info_tags' => array('keyword' => tagname, 'data' => tag description)
* known informational tags
* [ 'utags' => array('keyword' => tagname, 'data' => tag description
* [ 'vartype' => type from @var/@return tag ]
* [ 'var_descrip' => description from @var/@return tag ]
$tagses = $element->docblock ->listTags ();
$tags = $ret = $api_tags = $info_tags = array ();
$api_tags_arr = array ("abstract", "access", "deprecated", "example", "filesource",
"global", "internal", "name", "return", "see",
"property", "property-read", "property-write", "method",
"staticvar", "usedby", "uses", "var");
$tags[] = array ('keyword' => 'package','data' => $element->docblock ->package);
if (!empty ($element->docblock ->subpackage)) $tags[] = array ('keyword' => 'subpackage','data' => $element->docblock ->subpackage);
if ($element->docblock ->var )
$a = $element->docblock ->var ->Convert($this);
$ret['vartype'] = $element->docblock ->var ->converted_returnType;
$tags[] = array ('keyword' => 'var', 'data' => $a);
$ret["var_descrip"] = $a;
if ($element->docblock ->return )
$a = $element->docblock ->return ->Convert($this);
$ret['vartype'] = $element->docblock ->return ->converted_returnType;
$tags[] = $api_tags[] = array ('keyword' => 'return', 'data' => $a);
$ret["var_descrip"] = $a;
if ($element->docblock ->funcglobals )
foreach($element->docblock ->funcglobals as $global => $val)
$tags[] = $api_tags[] = array ('keyword' => 'global','data' => $val[0 ]. ' '. $global. ': '. $val[1 ]->Convert($this));
if ($element->docblock ->statics )
foreach($element->docblock ->statics as $static => $val)
$tags[] = $api_tags[] = array ('keyword' => 'staticvar','data' => $val->converted_returnType. ' '. $static. ': '. $a);
$property_tags = array ();
foreach ( $element->docblock ->properties as $prop_name => $val )
$tags[] = $api_tags[] = array ( 'keyword' => $val->keyword ,
'data' => $val->converted_returnType . ' ' . $prop_name . ': ' . $a );
$prop['prop_name'] = $prop_name;
$prop['access'] = $val->keyword == 'property-read' ? 'read' :
( $val->keyword == 'property-write' ? 'write' : 'read/write' );
$prop['prop_type'] = $val->converted_returnType;
$property_tags[ $prop_name ] = $prop;
ksort( $property_tags, SORT_STRING );
$info_tags_sorted = array ();
if (isset ($names[$tag->keyword ])) $tag->keyword = $names[$tag->keyword ];
if ($tag->keyword == 'static') {
$tags[] = array ("keyword" => $tag->keyword ,"data" => $tag->Convert($this));
if (in_array($tag->keyword , $api_tags_arr)) {
$api_tags[] = array ("keyword" => $tag->keyword ,"data" => $tag->Convert($this));
$info_tags[] = array ("keyword" => $tag->keyword ,"data" => $tag->Convert($this));
$info_tags_sorted[ $tag->keyword ][] = array ( 'keyword' => $className, 'data' => $desc );
foreach($element->docblock ->unknown_tags as $keyword => $tag)
$utags[] = array ('keyword' => $keyword, 'data' => $t->Convert($this));
$ret['abstract'] = false;
$ret['access'] = 'public';
if ($tag['keyword'] == 'access') {
$ret['access'] = $tag['data'];
if ($tag['keyword'] == 'abstract') {
if ($tag['keyword'] == 'see' || $tag['keyword'] == 'uses' ||
$tag['keyword'] == 'usedby') {
$see_tags[] = $tag['data'];
$ret['sdesc'] = $element->docblock ->getSDesc ($this);
$ret['desc'] = $element->docblock ->getDesc ($this);
$ret['see_tags'] = $see_tags;
$ret['info_tags_sorted'] = $info_tags_sorted;
$ret['api_tags'] = $api_tags;
$ret['info_tags'] = $info_tags;
$ret['property_tags'] = $property_tags;
* gets a list of all classes declared on a procedural page represented by
* $element, a {@link parserData} class
* @param parserData &$element
* @return array links to each classes documentation
* array('name' => class name,
* 'sdesc' => summary of the class
* 'link' => link to the class's documentation)
global $_phpDocumentor_setting;
$a = $element->getClasses ($this);
foreach($a as $package => $clas)
if (!empty ($_phpDocumentor_setting['packageoutput']))
$packages = explode(',',$_phpDocumentor_setting['packageoutput']);
if (!in_array($package, $packages)) continue;
for($i=0; $i< count($clas); $i++ )
if ($this->parseprivate || ! ($clas[$i]->docblock && $clas[$i]->docblock ->hasaccess && $clas[$i]->docblock ->tags ['access'][0 ]->value == 'private'))
$sdesc = $clas[$i]->docblock ->getSDesc ($this);
if ($clas[$i]->docblock ->hasaccess )
$r['access'] = $clas[$i]->docblock ->tags ['access'][0 ]->value;
if (isset ($clas[$i]->docblock ->tags ['abstract']))
$r['name'] = $clas[$i]->getName ();
$r['link'] = $this->getClassLink($clas[$i]->getName (),$package,$clas[$i]->getPath ());
* returns an array containing the class inheritance tree from the root
* This method must be overridden, or phpDocumentor will halt with a fatal
* @return string Converter-specific class tree for an individual class
* @param parserClass class variable
* returns an array containing the class inheritance tree from the root
* This method must be overridden, or phpDocumentor will halt with a fatal
* @return string Converter-specific class tree for an individual class
* @param parserClass class variable
foreach ($el->getImplements () as $interface)
$link = $this->getLink($interface);
$inter = new ReflectionClass ($interface);
if ($inter->isInternal ()) {
$ret[] = $interface . ' (internal interface)';
* @param mixed {@link parserClass, parserFunction, parserDefine} or
* @param string type to display. either 'class','function','define'
* @return array links to conflicting elements, or empty array
* @uses parserClass::getConflicts()
* @uses parserFunction::getConflicts()
* @uses parserDefine::getConflicts()
* @uses parserGlobal::getConflicts()
$conflicts = $element->getConflicts ($this);
if (!$conflicts) return false;
foreach($conflicts as $package => $class)
if (!empty ($r)) $r = array ('conflicttype' => $type, 'conflicts' => $r);
* Get a list of methods in child classes that override this method
* @return array empty array or array(array('link'=>link to method,
* 'sdesc'=>short description of the method),...)
* @uses parserMethod::getOverridingMethods()
$meths = $element->getOverridingMethods ($this);
for($i=0; $i< count($meths); $i++ )
$ms['link'] = $meths[$i]->getLink($this);
$ms['sdesc'] = $meths[$i]->docblock ->getSDesc ($this);
* Get a list of vars in child classes that override this var
* @return array empty array or array('link'=>link to var,
* 'sdesc'=>short description of the method
* @uses parserVar::getOverridingVars()
$vars = $element->getOverridingVars ($this);
for($i=0; $i< count($vars); $i++ )
$vs['link'] = $vars[$i]->getLink($this);
$vs['sdesc'] = $vars[$i]->docblock ->getSDesc ($this);
* Get the method this method overrides, if any
* @return array|falsearray('link'=>link to overridden method,
* 'sdesc'=>short description
* @see parserMethod::getOverrides()
$ovr = $element->getOverrides ($this);
$sdesc = $ovr->docblock ->getSDesc ($this);
$name = method_exists($ovr, 'getFunctionCall') ? $ovr->getFunctionCall () : $ovr->getName ();
$link = ($link = $ovr->getLink($this)) ? $link : $ovr->getClass () . '::' . $name;
return array ('link' => $link,'sdesc' => $sdesc);
* Get the method this method(s) implemented from an interface, if any
* @return array|falsearray('link'=>link to implemented method,
* 'sdesc'=>short description
* @uses parserMethod::getImplements()
$ovr = $element->getImplements ($this);
foreach ($ovr as $impl) {
$sdesc = $impl->docblock ->getSDesc ($this);
$name = $impl->getName ();
$link = ($link = $impl->getLink($this)) ? $link : $impl->getClass () . '::' . $name;
$ret[] = array ('link' => $link,'sdesc' => $sdesc);
* returns a list of child classes
* @param parserClass class variable
* @uses parserClass::getChildClassList()
$kids = $class->getChildClassList ($this);
for($i=0; $i< count($kids); $i++ )
$lt['link'] = $kids[$i]->getLink($this);
$lt['sdesc'] = $kids[$i]->docblock ->getSDesc ($this);
if ($kids[$i]->docblock ->hasaccess )
$lt['access'] = $kids[$i]->docblock ->tags ['access'][0 ]->value;
$lt['access'] = 'public';
$lt['abstract'] = isset ($kids[$i]->docblock ->tags ['abstract'][0 ]);
* Return template-enabled list of inherited variables
* uses parserVar helper function getInheritedVars and generates a
* template-enabled list using getClassLink()
* @param parserVar $child class var
* @see getClassLink(), parserVar::getInheritedVars()
* array('parent_class' => link to parent class's documentation,
* array('name' => inherited variable name,
* 'link' => link to inherited variable's documentation,
* 'default' => default value of inherited variable,
* 'sdesc' => summary of inherited variable),
$package = $child->docblock ->package;
$ivars = $child->getInheritedVars ($this);
if (!count($ivars)) return $results;
foreach($ivars as $parent => $vars)
$par = $this->classes->getClass ($parent,$file);
$package = $par->docblock ->package;
usort($vars,array ($this,"sortVar"));
$result['parent_class'] = $this->getClassLink($parent, $package);
if (!$result['parent_class']) {
$result['parent_class'] = $parent . ' (Internal Class)';
if ($var->docblock ->hasaccess ) {
$info['access'] = $var->docblock ->tags ['access'][0 ]->value;
$info['access'] = 'public';
$info['abstract'] = isset ($var->docblock ->tags ['abstract'][0 ]);
$info['name'] = $var->getName ();
$info['link'] = $var->getLink($this);
$info['link'] = $info['name'];
$info['default'] = $this->postProcess($var->getValue ());
$info['sdesc'] = $var->docblock ->getSDesc ($this);
$result["ivars"][] = $info;
* Return template-enabled list of inherited methods
* uses parserMethod helper function getInheritedMethods and generates a
* template-enabled list using getClassLink()
* @param parserMethod $child class method
* @see getClassLink(), parserMethod::getInheritedMethods()
* array('parent_class' => link to parent class's documentation,
* array('name' => inherited variable name,
* 'link' => link to inherited variable's documentation,
* 'function_call' => {@link parserMethod::getIntricateFunctionCall()}
* 'sdesc' => summary of inherited variable),
$package = $child->docblock ->package;
$imethods = $child->getInheritedMethods ($this);
if (!count($imethods)) return $results;
foreach($imethods as $parent => $methods)
$file = $methods['file'];
$methods = $methods['methods'];
$par = $this->classes->getClass ($parent,$file);
$package = $par->docblock ->package;
usort($methods,array ($this,"sortMethod"));
$result['parent_class'] = $this->getClassLink($parent,$package);
if (!$result['parent_class']) {
$result['parent_class'] = $parent . ' (Internal Class)';
foreach($methods as $method)
if ($method->docblock ->hasaccess ) {
$info['access'] = $method->docblock ->tags ['access'][0 ]->value;
$info['access'] = 'public';
$info['abstract'] = isset ($method->docblock ->tags ['abstract'][0 ]);
if ($method->isConstructor ) $info['constructor'] = 1;
if ($method->isConstructor ) {
$returntype = $method->getClass ();
if ($method->docblock ->return ) {
$a = $method->docblock ->return ->Convert($this);
$returntype = $method->docblock ->return ->converted_returnType;
$info['function_return'] = $returntype;
$info['static'] = isset ($method->docblock ->tags ['static'][0 ]);
$info['link'] = $method->getLink($this);
$info['link'] = $method->getFunctionCall ();
$info['name'] = $method->getName ();
$info['sdesc'] = $method->docblock ->getSDesc ($this);
if (count($method->docblock ->params ))
foreach($method->docblock ->params as $param => $val)
$params[$param] = array ("var" => $param,"datatype" => $val->converted_returnType ,"data" => $a);
$info['function_call'] = $method->getIntricateFunctionCall ($this,$params);
$result["imethods"][] = $info;
* Return template-enabled list of inherited class constants
* uses parserConst helper function getInheritedConsts and generates a
* template-enabled list using getClassLink()
* @param parserConst $child class constant
* @see getClassLink(), parserMethod::getInheritedConsts()
* array('parent_class' => link to parent class's documentation,
* array('name' => inherited constant name,
* 'link' => link to inherited constant's documentation,
* 'value' => constant value,
* 'sdesc' => summary of inherited constant),
$package = $child->docblock ->package;
$ivars = $child->getInheritedConsts ($this);
if (!count($ivars)) return $results;
foreach($ivars as $parent => $vars)
$par = $this->classes->getClass ($parent,$file);
$package = $par->docblock ->package;
usort($vars,array ($this,"sortVar"));
$result['parent_class'] = $this->getClassLink($parent,$package);
if (!$result['parent_class']) {
$result['parent_class'] = $parent . ' (Internal Class)';
if ($var->docblock ->hasaccess ) {
$info['access'] = $var->docblock ->tags ['access'][0 ]->value;
$info['access'] = 'public';
$info['name'] = $var->getName ();
$info['link'] = $var->getLink($this);
$info['link'] = $info['name'] . ' = ' . $var->getValue ();
$info['sdesc'] = $var->docblock ->getSDesc ($this);
$result["iconsts"][] = $info;
* Return a Smarty template object to operate with
* This returns a Smarty template with pre-initialized variables for use.
* If the method "SmartyInit()" exists, it is called.
$templ->use_sub_dirs = false;
// we'll delete this on finishing conversion
$this->_compiledDir [$this->targetDir . DIRECTORY_SEPARATOR . md5($templatename)] = 1;
$templ->assign ("date",date("r",time()));
$templ->assign ("maintitle",$this->title);
$templ->assign ("charset",$this->charset);
$templ->assign ('default_package',$GLOBALS['phpDocumentor_DefaultPackageName']);
$templ->assign ("package",$this->package);
if (method_exists($this,'SmartyInit')) return $this->SmartyInit ($templ);
* Finish up parsing/cleanup directories
foreach ($this->_compiledDir as $dir => $one) {
* Completely remove a directory and its contents
* @param string $directory
function _rmdir ($directory)
while (false !== ($file = readdir($handle))) {
if ($file == '.' || $file == '..') {
if (is_dir($directory . DIRECTORY_SEPARATOR . $file)) {
$this->_rmdir ($directory . DIRECTORY_SEPARATOR . $file);
@unlink($directory . DIRECTORY_SEPARATOR . $file);
* do all necessary output
phpDocumentor_out("WARNING: Generic Converter::Output was used, no output will be generated");
* Set the template directory with a different template base directory
* @tutorial phpDocumentor.howto.pkg#using.command-line.templatebase
* @param string template base directory
* @param string template name
// remove trailing /'s from the base path, if any
// retrieve template options, allow array creation
* sets the template directory based on the {@link $outputformat} and {@link $name}
* Also sets {@link $templateName} to the $dir parameter
* @param string subdirectory
if (isset ($GLOBALS['_phpDocumentor_template_base'])) {
$templateBase = str_replace('\\', '/', $GLOBALS['_phpDocumentor_template_base']);
} else if ('@DATA-DIR@' != '@'. 'DATA-DIR@') {
$templateBase = str_replace('\\', '/', '@DATA-DIR@/PhpDocumentor/phpDocumentor');
$templateBase = str_replace('\\','/',$GLOBALS['_phpDocumentor_install_dir']) . '/phpDocumentor';
* Get the absolute path to the converter's base directory
if ('@DATA-DIR@' != '@' . 'DATA-DIR@') {
return str_replace('\\', '/', "@DATA-DIR@/PhpDocumentor/phpDocumentor/Converters/") . $this->outputformat . "/" . $this->name;
return str_replace('\\','/',$GLOBALS['_phpDocumentor_install_dir']) . "/phpDocumentor/Converters/" . $this->outputformat . "/" . $this->name;
* Parse a global variable's default value for class initialization.
* If a global variable's default value is "new class" as in:
* $globalvar = new Parser
* This method will document it not as "new Parser" but instead as
* "new {@link Parser}". For examples, see {@link phpdoc.inc}.
* Many global variables are classes, and phpDocumentor links to their
* @return string default global variable value with link to class if
* @param string default value of a global variable.
if (strpos($value,'new') === 0 )
preg_match('/new([^(]*)((?:.|\r|\n)*)/',$value,$newval);
if (!isset ($newval[2 ])) $newval[2 ] = '';
* Parse an include's file to see if it is a file documented in this project
* Although not very smart yet, this method will try to look for the
* included file file.ext:
* If it finds it, it will return a link to the file's documentation. As of
* 1.2.0rc1, phpDocumentor is smarty enough to find these cases:
* <li>absolute path to file</li>
* <li>./file.ext or ../file.ext</li>
* <li>relpath/to/file.ext if relpath is a subdirectory of the base parse
* For examples, see {@link Setup.inc.php} includes.
* Every include auto-links to the documentation for the file that is included
* @return string included file with link to docs for file, if found
* @param string file included by include statement.
* @param string path of file that has the include statement
preg_match('/"([^"\']*\.[^"\']*)"/',$value,$match);
preg_match('/\'([^"\']*\.[^"\']*)\'/',$value,$match);
$fancy_per = $this->proceduralpages ->pathMatchesParsedFile ($match[1 ],$ipath);
$link = $this->addLink ($fancy_per);
* Recursively creates all subdirectories that don't exist in the $dir path
$test = @mkdir($parent,0775 );
$test = @mkdir($parent,0775 );
* Sets the output directory for generated documentation
* As of 1.3.0RC6, this also sets the compiled templates directory inside
* @param string $dir the output directory
// if directory does exist create it, this should have more error checking in the future
echo " Output path: '$dir' is not a directory\n";
echo "a target directory must be specified\n try phpdoc -h\n";
* Writes a file to target dir
* @param boolean true if the data is binary and not text
function writeFile($file,$data,$binary = false )
if ($binary) $string = 'binary file ';
if ($binary) $write = 'wb';
* Copies a file from the template directory to the target directory
* thanks to Robert Hoffmann for this fix
* Return parserStringWithInlineTags::Convert() cache state
* @see parserStringWithInlineTags::Convert()
* Compare parserStringWithInlineTags::Convert() cache state to $state
* @see parserStringWithInlineTags::Convert()
* @see Converter::getSortedClassTreeFromClass()
* @global string used to make the first tutorials converted the default package tutorials
function tutorialcmp ($a, $b)
global $phpDocumentor_DefaultPackageName;
if ($a == $phpDocumentor_DefaultPackageName) return -1;
if ($b == $phpDocumentor_DefaultPackageName) return 1;
* smart htmlentities, doesn't entity the allowed tags list
* Since version 1.1, this function uses htmlspecialchars instead of
* htmlentities, for international support
* This function has been replaced by functionality in {@link ParserDescCleanup.inc}
* @return string browser-displayable page
* @deprecated As of v1.2, No longer needed, as valid tags are parsed out of the source,
* and everything else is {@link Converter::postProcess()} handled
global $phpDocumentor___html,$_phpDocumentor_html_allowed;
$result = strtr($result,$phpDocumentor___html);
for($i=0; $i< count($matches[1 ]); $i++ )
for($i=0; $i< count($matches[1 ]); $i++ )
for($i=0; $i< count($matches[1 ]); $i++ )
for($i=0; $i< count($matches[1 ]); $i++ )
for($i=0; $i< count($matches[1 ]); $i++ )
for($i=0; $i< count($matches[1 ]); $i++ )
* Used solely for setting up the @uses list
function setTemplateDir (){}
function setTargetDir (){}
function getPageName (&$element)
return '_'. $element->parent ->getName ();
Documentation generated on Mon, 11 Mar 2019 15:50:16 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|