PageRenderTime 82ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/secured/phpDocumentor/phpDocumentor/Converter.inc

http://oregon-caspages.googlecode.com/
PHP | 5456 lines | 3509 code | 203 blank | 1744 comment | 743 complexity | 1ea9a6550994bf333f43d006e47affe2 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, AGPL-3.0
  1. <?php
  2. /**
  3. * Base class for all Converters
  4. *
  5. * phpDocumentor :: automatic documentation generator
  6. *
  7. * PHP versions 4 and 5
  8. *
  9. * Copyright (c) 2001-2006 Gregory Beaver
  10. *
  11. * LICENSE:
  12. *
  13. * This library is free software; you can redistribute it
  14. * and/or modify it under the terms of the GNU Lesser General
  15. * Public License as published by the Free Software Foundation;
  16. * either version 2.1 of the License, or (at your option) any
  17. * later version.
  18. *
  19. * This library is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  22. * Lesser General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU Lesser General Public
  25. * License along with this library; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  27. *
  28. * @package Converters
  29. * @author Greg Beaver <cellog@php.net>
  30. * @copyright 2001-2006 Gregory Beaver
  31. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  32. * @version CVS: $Id: Converter.inc,v 1.39 2007/12/19 02:16:49 ashnazg Exp $
  33. * @filesource
  34. * @link http://www.phpdoc.org
  35. * @link http://pear.php.net/PhpDocumentor
  36. * @see parserDocBlock, parserInclude, parserPage, parserClass
  37. * @see parserDefine, parserFunction, parserMethod, parserVar
  38. * @since 1.0rc1
  39. */
  40. /**
  41. * Smarty template files
  42. */
  43. include_once("phpDocumentor/Smarty-2.6.0/libs/Smarty.class.php");
  44. /**
  45. * Base class for all output converters.
  46. *
  47. * The Converter marks the final stage in phpDocumentor. phpDocumentor works
  48. * in this order:
  49. *
  50. * <pre>Parsing => Intermediate Parsing organization => Conversion to output</pre>
  51. *
  52. * A Converter takes output from the {@link phpDocumentor_IntermediateParser} and
  53. * converts it to output. With version 1.2, phpDocumentor includes a variety
  54. * of output converters:
  55. * <ul>
  56. * <li>{@link HTMLframesConverter}</li>
  57. * <li>{@link HTMLSmartyConverter}</li>
  58. * <li>{@link PDFdefaultConverter}</li>
  59. * <li>{@link CHMdefaultConverter}</li>
  60. * <li>{@link CSVdia2codeConverter}</li>
  61. * <li>{@link XMLDocBookConverter}</li>
  62. * </ul>
  63. * {@internal
  64. * The converter takes output directly from {@link phpDocumentor_IntermediateParser}
  65. * and using {@link walk()} or {@link walk_everything} (depending on the value of
  66. * {@link $sort_absolutely_everything}) it "walks" over an array of phpDocumentor elements.}}
  67. *
  68. * @package Converters
  69. * @abstract
  70. * @author Greg Beaver <cellog@php.net>
  71. * @since 1.0rc1
  72. * @version $Id: Converter.inc,v 1.39 2007/12/19 02:16:49 ashnazg Exp $
  73. */
  74. class Converter
  75. {
  76. /**
  77. * This converter knows about the new root tree processing
  78. * In order to fix PEAR Bug #6389
  79. * @var boolean
  80. */
  81. var $processSpecialRoots = false;
  82. /**
  83. * output format of this converter
  84. *
  85. * in Child converters, this will match the first part of the -o command-line
  86. * as in -o HTML:frames:default "HTML"
  87. * @tutorial phpDocumentor.howto.pkg#using.command-line.output
  88. * @var string
  89. */
  90. var $outputformat = 'Generic';
  91. /**
  92. * package name currently being converted
  93. * @var string
  94. */
  95. var $package = 'default';
  96. /**
  97. * subpackage name currently being converted
  98. * @var string
  99. */
  100. var $subpackage = '';
  101. /**
  102. * set to a classname if currently parsing a class, false if not
  103. * @var string|false
  104. */
  105. var $class = false;
  106. /**#@+
  107. * @access private
  108. */
  109. /**
  110. * the workhorse of linking.
  111. *
  112. * This array is an array of link objects of format:
  113. * [package][subpackage][eltype][elname] = descendant of {@link abstractLink}
  114. * eltype can be page|function|define|class|method|var
  115. * if eltype is method or var, the array format is:
  116. * [package][subpackage][eltype][class][elname]
  117. * @var array
  118. * @see functionLink, pageLink, classLink, defineLink, methodLink, varLink, globalLink
  119. */
  120. var $links = array();
  121. /**
  122. * the workhorse of linking, with allowance for support of multiple
  123. * elements in different files.
  124. *
  125. * This array is an array of link objects of format:
  126. * [package][subpackage][eltype][file][elname] = descendant of {@link abstractLink}
  127. * eltype can be function|define|class|method|var
  128. * if eltype is method or var, the array format is:
  129. * [package][subpackage][eltype][file][class][elname]
  130. * @var array
  131. * @see functionLink, pageLink, classLink, defineLink, methodLink, varLink, globalLink
  132. */
  133. var $linkswithfile = array();
  134. /**#@-*/
  135. /**
  136. * set to value of -po commandline
  137. * @tutorial phpDocumentor.howto.pkg#using.command-line.packageoutput
  138. * @var mixed
  139. */
  140. var $package_output;
  141. /**
  142. * name of current page being converted
  143. * @var string
  144. */
  145. var $page;
  146. /**
  147. * path of current page being converted
  148. * @var string
  149. */
  150. var $path;
  151. /**
  152. * template for the procedural page currently being processed
  153. * @var Smarty
  154. */
  155. var $page_data;
  156. /**
  157. * template for the class currently being processed
  158. * @var Smarty
  159. */
  160. var $class_data;
  161. /**
  162. * current procedural page being processed
  163. * @var parserPage
  164. */
  165. var $curpage;
  166. /**
  167. * alphabetical index of all elements sorted by package, subpackage, page,
  168. * and class.
  169. * @var array Format: array(package => array(subpackage => array('page'|'class' => array(path|classname => array(element, element,...)))))
  170. * @uses $sort_absolutely_everything if true, then $package_elements is used,
  171. * otherwise, the {@link ParserData::$classelements} and
  172. * {@link ParserData::$pageelements} variables are used
  173. */
  174. var $package_elements = array();
  175. /**
  176. * alphabetical index of all elements
  177. *
  178. * @var array Format: array(first letter of element name => array({@link parserElement} or {@link parserPage},...))
  179. * @see formatIndex(), HTMLframesConverter::formatIndex()
  180. */
  181. var $elements = array();
  182. /**
  183. * alphabetized index of procedural pages by package
  184. *
  185. * @see $leftindex
  186. * @var array Format: array(package => array(subpackage => array({@link pageLink} 1,{@link pageLink} 2,...)
  187. */
  188. var $page_elements = array();
  189. /**
  190. * alphabetized index of defines by package
  191. *
  192. * @see $leftindex
  193. * @var array Format: array(package => array(subpackage => array({@link defineLink} 1,{@link defineLink} 2,...)
  194. */
  195. var $define_elements = array();
  196. /**
  197. * alphabetized index of classes by package
  198. *
  199. * @see $leftindex
  200. * @var array Format: array(package => array(subpackage => array({@link classLink} 1,{@link classLink} 2,...)
  201. */
  202. var $class_elements = array();
  203. /**
  204. * alphabetized index of global variables by package
  205. *
  206. * @see $leftindex
  207. * @var array Format: array(package => array(subpackage => array({@link globalLink} 1,{@link globalLink} 2,...)
  208. */
  209. var $global_elements = array();
  210. /**
  211. * alphabetized index of functions by package
  212. *
  213. * @see $leftindex
  214. * @var array Format: array(package => array(subpackage => array({@link functionLink} 1,{@link functionLink} 2,...)
  215. */
  216. var $function_elements = array();
  217. /**
  218. * alphabetical index of all elements, indexed by package/subpackage
  219. *
  220. * @var array Format: array(first letter of element name => array({@link parserElement} or {@link parserPage},...))
  221. * @see formatPkgIndex(), HTMLframesConverter::formatPkgIndex()
  222. */
  223. var $pkg_elements = array();
  224. /**
  225. * alphabetical index of all elements on a page by package/subpackage
  226. *
  227. * The page itself has a link under ###main
  228. * @var array Format: array(package => array(subpackage => array(path => array({@link abstractLink} descendant 1, ...)))
  229. * @see formatLeftIndex()
  230. */
  231. var $page_contents = array();
  232. /**
  233. * This determines whether the {@link $page_contents} array should be sorted by element type as well as alphabetically by name
  234. * @see sortPageContentsByElementType()
  235. * @var boolean
  236. */
  237. var $sort_page_contents_by_type = false;
  238. /**
  239. * This is used if the content must be passed in the order it should be read, i.e. by package, procedural then classes
  240. *
  241. * This fixes bug 637921, and is used by {@link PDFdefaultConverter}
  242. */
  243. var $sort_absolutely_everything = false;
  244. /**
  245. * alphabetical index of all methods and vars in a class by package/subpackage
  246. *
  247. * The class itself has a link under ###main
  248. * @var array
  249. * Format:<pre>
  250. * array(package =>
  251. * array(subpackage =>
  252. * array(path =>
  253. * array(class =>
  254. * array({@link abstractLink} descendant 1, ...
  255. * )
  256. * )
  257. * )
  258. * )</pre>
  259. * @see formatLeftIndex()
  260. */
  261. var $class_contents = array();
  262. /**
  263. * controls processing of elements marked private with @access private
  264. *
  265. * defaults to false. Set with command-line --parseprivate or -pp
  266. * @var bool
  267. */
  268. var $parseprivate;
  269. /**
  270. * controls display of progress information while parsing.
  271. *
  272. * defaults to false. Set to true for cron jobs or other situations where no visual output is necessary
  273. * @var bool
  274. */
  275. var $quietmode;
  276. /**
  277. * directory that output is sent to. -t command-line sets this.
  278. * @tutorial phpDocumentor.howto.pkg#using.command-line.target
  279. */
  280. var $targetDir = '';
  281. /**
  282. * Directory that the template is in, relative to phpDocumentor root directory
  283. * @var string
  284. */
  285. var $templateDir = '';
  286. /**
  287. * Directory that the smarty templates are in
  288. * @var string
  289. */
  290. var $smarty_dir = '';
  291. /**
  292. * Name of the template, from last part of -o
  293. * @tutorial phpDocumentor.howto.pkg#using.command-line.output
  294. * @var string
  295. */
  296. var $templateName = '';
  297. /**
  298. * full path of the current file being converted
  299. */
  300. var $curfile;
  301. /**
  302. * All class information, organized by path, and by package
  303. * @var Classes
  304. */
  305. var $classes;
  306. /**
  307. * Flag used to help converters determine whether to do special source highlighting
  308. * @var boolean
  309. */
  310. var $highlightingSource = false;
  311. /**
  312. * Hierarchy of packages
  313. *
  314. * Every package that contains classes may have parent or child classes
  315. * in other packages. In other words, this code is legal:
  316. *
  317. * <code>
  318. * /**
  319. * * @package one
  320. * * /
  321. * class one {}
  322. *
  323. * /**
  324. * * @package two
  325. * * /
  326. * class two extends one {}
  327. * </code>
  328. *
  329. * In this case, package one is a parent of package two
  330. * @var array
  331. * @see phpDocumentor_IntermediateParser::$package_parents
  332. */
  333. var $package_parents;
  334. /**
  335. * Packages associated with categories
  336. *
  337. * Used by the XML:DocBook/peardoc2 converter, and available to others, to
  338. * group many packages into categories
  339. * @see phpDocumentor_IntermediateParser::$packagecategories
  340. * @var array
  341. */
  342. var $packagecategories;
  343. /**
  344. * All packages encountered in parsing
  345. * @var array
  346. * @see phpDocumentor_IntermediateParser::$all_packages
  347. */
  348. var $all_packages;
  349. /**
  350. * A list of files that have had source code generated
  351. * @var array
  352. */
  353. var $sourcePaths = array();
  354. /**
  355. * Controls which of the one-element-only indexes are generated.
  356. *
  357. * Generation of these indexes for large packages is time-consuming. This is an optimization feature. An
  358. * example of how to use this is in {@link HTMLframesConverter::$leftindex}, and in {@link HTMLframesConverter::formatLeftIndex()}.
  359. * These indexes are intended for use as navigational aids through documentation, but can be used for anything by converters.
  360. * @see $class_elements, $page_elements, $function_elements, $define_elements, $global_elements
  361. * @see formatLeftIndex()
  362. * @var array
  363. */
  364. var $leftindex = array('classes' => true, 'pages' => true, 'functions' => true, 'defines' => true, 'globals' => true);
  365. /** @access private */
  366. var $killclass = false;
  367. /**
  368. * @var string
  369. * @see phpDocumentor_IntermediateParser::$title
  370. */
  371. var $title = 'Generated Documentation';
  372. /**
  373. * Options for each template, parsed from the options.ini file in the template base directory
  374. * @tutorial phpDocumentor/tutorials.pkg#conversion.ppage
  375. * @var array
  376. */
  377. var $template_options;
  378. /**
  379. * Tutorials and Extended Documentation parsed from a tutorials/package[/subpackage] directory
  380. * @tutorial tutorials.pkg
  381. * @access private
  382. */
  383. var $tutorials = array();
  384. /**
  385. * tree-format structure of tutorials and their child tutorials, if any
  386. * @var array
  387. * @access private
  388. */
  389. var $tutorial_tree = false;
  390. /**
  391. * list of tutorials that have already been processed. Used by @link _setupTutorialTree()
  392. * @var array
  393. * @access private
  394. */
  395. var $processed_tutorials;
  396. /**
  397. * List of all @todo tags and a link to the element with the @todo
  398. *
  399. * Format: array(package => array(link to element, array(todo {@link parserTag},...)),...)
  400. * @tutorial tags.todo.pkg
  401. * @var array
  402. */
  403. var $todoList = array();
  404. /**
  405. * Directory where compiled templates go - will be deleted on exit
  406. *
  407. * @var string
  408. * @access private
  409. */
  410. var $_compiledDir = array();
  411. /**
  412. * Initialize Converter data structures
  413. * @param array {@link $all_packages} value
  414. * @param array {@link $package_parents} value
  415. * @param Classes {@link $classes} value
  416. * @param ProceduralPages {@link $proceduralpages} value
  417. * @param array {@link $package_output} value
  418. * @param boolean {@link $parseprivate} value
  419. * @param boolean {@link $quietmode} value
  420. * @param string {@link $targetDir} value
  421. * @param string {@link $templateDir} value
  422. * @param string (@link $title} value
  423. */
  424. function Converter(&$allp, &$packp, &$classes, &$procpages, $po, $pp, $qm, $targetDir, $template, $title)
  425. {
  426. $this->all_packages = $allp;
  427. $this->package_parents = $packp;
  428. $this->package = $GLOBALS['phpDocumentor_DefaultPackageName'];
  429. $this->proceduralpages = &$procpages;
  430. $this->package_output = $po;
  431. if (is_array($po))
  432. {
  433. $a = $po[0];
  434. $this->all_packages = array_flip($po);
  435. $this->all_packages[$a] = 1;
  436. }
  437. $this->parseprivate = $pp;
  438. $this->quietmode = $qm;
  439. $this->classes = &$classes;
  440. $this->roots = $classes->getRoots($this->processSpecialRoots);
  441. $this->title = $title;
  442. $this->setTemplateDir($template);
  443. $this->setTargetdir($targetDir);
  444. }
  445. /**
  446. * Called by IntermediateParser after creation
  447. * @access private
  448. */
  449. function setTutorials($tutorials)
  450. {
  451. $this->tutorials = $tutorials;
  452. }
  453. /**
  454. * @param pkg|cls|proc the tutorial type to search for
  455. * @param tutorial name
  456. * @param string package name
  457. * @param string subpackage name, if any
  458. * @return false|parserTutorial if the tutorial exists, return it
  459. */
  460. function hasTutorial($type, $name, $package, $subpackage = '')
  461. {
  462. if (isset($this->tutorials[$package][$subpackage][$type][$name . '.' . $type]))
  463. return $this->tutorials[$package][$subpackage][$type][$name . '.' . $type];
  464. return false;
  465. }
  466. /**
  467. * Called by {@link walk()} while converting, when the last class element
  468. * has been parsed.
  469. *
  470. * A Converter can use this method in any way it pleases. HTMLframesConverter
  471. * uses it to complete the template for the class and to output its
  472. * documentation
  473. * @see HTMLframesConverter::endClass()
  474. * @abstract
  475. */
  476. function endClass()
  477. {
  478. }
  479. /**
  480. * Called by {@link walk()} while converting, when the last procedural page
  481. * element has been parsed.
  482. *
  483. * A Converter can use this method in any way it pleases. HTMLframesConverter
  484. * uses it to complete the template for the procedural page and to output its
  485. * documentation
  486. * @see HTMLframesConverter::endClass()
  487. * @abstract
  488. */
  489. function endPage()
  490. {
  491. }
  492. /**
  493. * Called by {@link walk()} while converting.
  494. *
  495. * This method is intended to be the place that {@link $pkg_elements} is
  496. * formatted for output.
  497. * @see HTMLframesConverter::formatPkgIndex()
  498. * @abstract
  499. */
  500. function formatPkgIndex()
  501. {
  502. }
  503. /**
  504. * Called by {@link walk()} while converting.
  505. *
  506. * This method is intended to be the place that {@link $elements} is
  507. * formatted for output.
  508. * @see HTMLframesConverter::formatIndex()
  509. * @abstract
  510. */
  511. function formatIndex()
  512. {
  513. }
  514. /**
  515. * Called by {@link walk()} while converting.
  516. *
  517. * This method is intended to be the place that any of
  518. * {@link $class_elements, $function_elements, $page_elements},
  519. * {@link $define_elements}, and {@link $global_elements} is formatted for
  520. * output, depending on the value of {@link $leftindex}
  521. * @see HTMLframesConverter::formatLeftIndex()
  522. * @abstract
  523. */
  524. function formatLeftIndex()
  525. {
  526. }
  527. /**
  528. * Called by {@link parserSourceInlineTag::stringConvert()} to allow
  529. * converters to format the source code the way they'd like.
  530. *
  531. * default returns it unchanged (html with xhtml tags)
  532. * @param string output from highlight_string() - use this function to
  533. * reformat the returned data for Converter-specific output
  534. * @return string
  535. * @deprecated in favor of tokenizer-based highlighting. This will be
  536. * removed for 2.0
  537. */
  538. function unmangle($sourcecode)
  539. {
  540. return $sourcecode;
  541. }
  542. /**
  543. * Initialize highlight caching
  544. */
  545. function startHighlight()
  546. {
  547. $this->_highlightCache = array(false, false);
  548. $this->_appendHighlight = '';
  549. }
  550. function getHighlightState()
  551. {
  552. return $this->_highlightCache;
  553. }
  554. function _setHighlightCache($type, $token)
  555. {
  556. $test = ($this->_highlightCache[0] === $type && $this->_highlightCache[1] == $token);
  557. if (!$test) {
  558. $this->_appendHighlight = $this->flushHighlightCache();
  559. } else {
  560. $this->_appendHighlight = '';
  561. }
  562. $this->_highlightCache = array($type, $token);
  563. return $test;
  564. }
  565. /**
  566. * Return the close text for the current token
  567. * @return string
  568. */
  569. function flushHighlightCache()
  570. {
  571. $hc = $this->_highlightCache;
  572. $this->_highlightCache = array(false, false);
  573. if ($hc[0]) {
  574. if (!isset($this->template_options[$hc[0]]['/'.$hc[1]])) {
  575. return '';
  576. }
  577. return $this->template_options[$hc[0]]['/'.$hc[1]];
  578. }
  579. return '';
  580. }
  581. /**
  582. * Used to allow converters to format the source code the way they'd like.
  583. *
  584. * default returns it unchanged. Mainly used by the {@link HighlightParser}
  585. * {@internal
  586. * The method takes information from options.ini, the template options
  587. * file, specifically the [highlightSourceTokens] and [highlightSource]
  588. * sections, and uses them to enclose tokens.
  589. *
  590. * {@source}}}
  591. * @param integer token value from {@link PHP_MANUAL#tokenizer tokenizer constants}
  592. * @param string contents of token
  593. * @param boolean whether the contents are preformatted or need modification
  594. * @return string
  595. */
  596. function highlightSource($token, $word, $preformatted = false)
  597. {
  598. if ($token !== false)
  599. {
  600. if (!$preformatted) $word = $this->postProcess($word);
  601. if (isset($this->template_options['highlightSourceTokens'][token_name($token)]))
  602. {
  603. if ($this->_setHighlightCache('highlightSourceTokens', token_name($token))) {
  604. return $word;
  605. }
  606. $e = $this->_appendHighlight;
  607. return $e . $this->template_options['highlightSourceTokens'][token_name($token)] . $word;
  608. } else
  609. {
  610. $this->_setHighlightCache(false, false);
  611. $e = $this->_appendHighlight;
  612. return $e . $word;
  613. }
  614. } else
  615. {
  616. if (isset($this->template_options['highlightSource'][$word]))
  617. {
  618. $newword = ($preformatted ? $word : $this->postProcess($word));
  619. if ($this->_setHighlightCache('highlightSource', $word)) {
  620. return $newword;
  621. }
  622. $e = $this->_appendHighlight;
  623. return $e . $this->template_options['highlightSource'][$word] . $newword;
  624. } else
  625. {
  626. $this->_setHighlightCache(false, false);
  627. $e = $this->_appendHighlight;
  628. return $e . ($preformatted ? $word : $this->postProcess($word));
  629. }
  630. }
  631. }
  632. /**
  633. * Used to allow converters to format the source code of DocBlocks the way
  634. * they'd like.
  635. *
  636. * default returns it unchanged. Mainly used by the {@link HighlightParser}
  637. * {@internal
  638. * The method takes information from options.ini, the template options
  639. * file, specifically the [highlightDocBlockSourceTokens] section, and uses
  640. * it to enclose tokens.
  641. *
  642. * {@source}}}
  643. * @param string name of docblock token type
  644. * @param string contents of token
  645. * @param boolean whether the contents are preformatted or need modification
  646. * @return string
  647. */
  648. function highlightDocBlockSource($token, $word, $preformatted = false)
  649. {
  650. if (empty($word)) {
  651. $this->_setHighlightCache(false, false);
  652. $e = $this->_appendHighlight;
  653. return $e . $word;
  654. }
  655. if (isset($this->template_options['highlightDocBlockSourceTokens'][$token]))
  656. {
  657. if (!$preformatted) $word = $this->postProcess($word);
  658. if ($this->_setHighlightCache('highlightDocBlockSourceTokens', $token)) {
  659. return $word;
  660. }
  661. $e = $this->_appendHighlight;
  662. return $e . $this->template_options['highlightDocBlockSourceTokens'][$token] . $word;
  663. } else {
  664. $this->_setHighlightCache(false, false);
  665. $e = $this->_appendHighlight;
  666. return $e . ($preformatted ? $word : $this->postProcess($word));
  667. }
  668. }
  669. /**
  670. * Used to allow converters to format the source code of Tutorial XML the way
  671. * they'd like.
  672. *
  673. * default returns it unchanged. Mainly used by the {@link HighlightParser}
  674. * {@internal
  675. * The method takes information from options.ini, the template options
  676. * file, specifically the [highlightDocBlockSourceTokens] section, and uses
  677. * it to enclose tokens.
  678. *
  679. * {@source}}}
  680. * @param string name of docblock token type
  681. * @param string contents of token
  682. * @param boolean whether the contents are preformatted or need modification
  683. * @return string
  684. */
  685. function highlightTutorialSource($token, $word, $preformatted = false)
  686. {
  687. if (empty($word)) {
  688. $this->_setHighlightCache(false, false);
  689. $e = $this->_appendHighlight;
  690. return $e . $word;
  691. }
  692. if (isset($this->template_options['highlightTutorialSourceTokens'][$token]))
  693. {
  694. if (!$preformatted) $word = $this->postProcess($word);
  695. if ($this->_setHighlightCache('highlightTutorialSourceTokens', $token)) {
  696. return $word;
  697. }
  698. $e = $this->_appendHighlight;
  699. return $e . $this->template_options['highlightTutorialSourceTokens'][$token] . $word;
  700. } else {
  701. $this->_setHighlightCache(false, false);
  702. $e = $this->_appendHighlight;
  703. return $e . ($preformatted ? $word : $this->postProcess($word));
  704. }
  705. }
  706. /**
  707. * Called by {@link parserReturnTag::Convert()} to allow converters to
  708. * change type names to desired formatting
  709. *
  710. * Used by {@link XMLDocBookConverter::type_adjust()} to change true and
  711. * false to the peardoc2 values
  712. * @param string
  713. * @return string
  714. */
  715. function type_adjust($typename)
  716. {
  717. return $typename;
  718. }
  719. /**
  720. * Used to convert the {@}example} inline tag in a docblock.
  721. *
  722. * By default, this just wraps ProgramExample
  723. * @see XMLDocBookpeardoc2Converter::exampleProgramExample
  724. * @param string
  725. * @param boolean true if this is to highlight a tutorial <programlisting>
  726. * @return string
  727. */
  728. function exampleProgramExample($example, $tutorial = false, $inlinesourceparse = null/*false*/,
  729. $class = null/*false*/, $linenum = null/*false*/, $filesourcepath = null/*false*/)
  730. {
  731. return $this->ProgramExample($example, $tutorial, $inlinesourceparse, $class, $linenum, $filesourcepath);
  732. }
  733. /**
  734. * Used to convert the <<code>> tag in a docblock
  735. * @param string
  736. * @param boolean true if this is to highlight a tutorial <programlisting>
  737. * @return string
  738. */
  739. function ProgramExample($example, $tutorial = false, $inlinesourceparse = null/*false*/,
  740. $class = null/*false*/, $linenum = null/*false*/, $filesourcepath = null/*false*/)
  741. {
  742. $this->highlightingSource = true;
  743. if (tokenizer_ext)
  744. {
  745. $e = $example;
  746. if (!is_array($example))
  747. {
  748. $obj = new phpDocumentorTWordParser;
  749. $obj->setup($example);
  750. $e = $obj->getFileSource();
  751. $bOpenTagFound = false;
  752. foreach ($e as $ke => $ee)
  753. {
  754. foreach ($ee as $kee => $eee)
  755. {
  756. if ((int) $e[$ke][$kee][0] == T_OPEN_TAG)
  757. {
  758. $bOpenTagFound = true;
  759. }
  760. }
  761. }
  762. if (!$bOpenTagFound) {
  763. $example = "<?php\n".$example;
  764. $obj->setup($example);
  765. $e = $obj->getFileSource();
  766. unset($e[0]);
  767. $e = array_values($e);
  768. }
  769. unset($obj);
  770. }
  771. $saveclass = $this->class;
  772. $parser = new phpDocumentor_HighlightParser;
  773. if (!isset($inlinesourceparse))
  774. {
  775. $example = $parser->parse($e, $this, true); // force php mode
  776. } else
  777. {
  778. if (isset($filesourcepath))
  779. {
  780. $example = $parser->parse($e, $this, $inlinesourceparse, $class, $linenum, $filesourcepath);
  781. } elseif (isset($linenum))
  782. {
  783. $example = $parser->parse($e, $this, $inlinesourceparse, $class, $linenum);
  784. } elseif (isset($class))
  785. {
  786. $example = $parser->parse($e, $this, $inlinesourceparse, $class);
  787. } else
  788. {
  789. $example = $parser->parse($e, $this, $inlinesourceparse);
  790. }
  791. }
  792. $this->class = $saveclass;
  793. } else
  794. {
  795. $example = $this->postProcess($example);
  796. }
  797. $this->highlightingSource = false;
  798. if ($tutorial)
  799. {
  800. return $example;
  801. }
  802. if (!isset($this->template_options['desctranslate'])) return $example;
  803. if (!isset($this->template_options['desctranslate']['code'])) return $example;
  804. $example = $this->template_options['desctranslate']['code'] . $example;
  805. if (!isset($this->template_options['desctranslate']['/code'])) return $example;
  806. return $example . $this->template_options['desctranslate']['/code'];
  807. }
  808. /**
  809. * @param string
  810. */
  811. function TutorialExample($example)
  812. {
  813. $this->highlightingSource = true;
  814. $parse = new phpDocumentor_TutorialHighlightParser;
  815. $x = $parse->parse($example, $this);
  816. $this->highlightingSource = false;
  817. return $x;
  818. }
  819. /**
  820. * Used to convert the contents of <<li>> in a docblock
  821. * @param string
  822. * @return string
  823. */
  824. function ListItem($item)
  825. {
  826. if (!isset($this->template_options['desctranslate'])) return $item;
  827. if (!isset($this->template_options['desctranslate']['li'])) return $item;
  828. $item = $this->template_options['desctranslate']['li'] . $item;
  829. if (!isset($this->template_options['desctranslate']['/li'])) return $item;
  830. return $item . $this->template_options['desctranslate']['/li'];
  831. }
  832. /**
  833. * Used to convert the contents of <<ol>> or <<ul>> in a docblock
  834. * @param string
  835. * @return string
  836. */
  837. function EncloseList($list,$ordered)
  838. {
  839. $listname = ($ordered ? 'ol' : 'ul');
  840. if (!isset($this->template_options['desctranslate'])) return $list;
  841. if (!isset($this->template_options['desctranslate'][$listname])) return $list;
  842. $list = $this->template_options['desctranslate'][$listname] . $list;
  843. if (!isset($this->template_options['desctranslate']['/'.$listname])) return $list;
  844. return $list . $this->template_options['desctranslate']['/'.$listname];
  845. }
  846. /**
  847. * Used to convert the contents of <<pre>> in a docblock
  848. * @param string
  849. * @return string
  850. */
  851. function PreserveWhiteSpace($string)
  852. {
  853. if (!isset($this->template_options['desctranslate'])) return $string;
  854. if (!isset($this->template_options['desctranslate']['pre'])) return $string;
  855. $string = $this->template_options['desctranslate']['pre'] . $string;
  856. if (!isset($this->template_options['desctranslate']['/pre'])) return $string;
  857. return $string . $this->template_options['desctranslate']['/pre'];
  858. }
  859. /**
  860. * Used to enclose a paragraph in a docblock
  861. * @param string
  862. * @return string
  863. */
  864. function EncloseParagraph($para)
  865. {
  866. if (!isset($this->template_options['desctranslate'])) return $para;
  867. if (!isset($this->template_options['desctranslate']['p'])) return $para;
  868. $para = $this->template_options['desctranslate']['p'] . $para;
  869. if (!isset($this->template_options['desctranslate']['/p'])) return $para;
  870. return $para . $this->template_options['desctranslate']['/p'];
  871. }
  872. /**
  873. * Used to convert the contents of <<b>> in a docblock
  874. * @param string
  875. * @return string
  876. */
  877. function Bolden($para)
  878. {
  879. if (!isset($this->template_options['desctranslate'])) return $para;
  880. if (!isset($this->template_options['desctranslate']['b'])) return $para;
  881. $para = $this->template_options['desctranslate']['b'] . $para;
  882. if (!isset($this->template_options['desctranslate']['/b'])) return $para;
  883. return $para . $this->template_options['desctranslate']['/b'];
  884. }
  885. /**
  886. * Used to convert the contents of <<i>> in a docblock
  887. * @param string
  888. * @return string
  889. */
  890. function Italicize($para)
  891. {
  892. if (!isset($this->template_options['desctranslate'])) return $para;
  893. if (!isset($this->template_options['desctranslate']['i'])) return $para;
  894. $para = $this->template_options['desctranslate']['i'] . $para;
  895. if (!isset($this->template_options['desctranslate']['/i'])) return $para;
  896. return $para . $this->template_options['desctranslate']['/i'];
  897. }
  898. /**
  899. * Used to convert the contents of <<var>> in a docblock
  900. * @param string
  901. * @return string
  902. */
  903. function Varize($para)
  904. {
  905. if (!isset($this->template_options['desctranslate'])) return $para;
  906. if (!isset($this->template_options['desctranslate']['var'])) return $para;
  907. $para = $this->template_options['desctranslate']['var'] . $para;
  908. if (!isset($this->template_options['desctranslate']['/var'])) return $para;
  909. return $para . $this->template_options['desctranslate']['/var'];
  910. }
  911. /**
  912. * Used to convert the contents of <<kbd>> in a docblock
  913. * @param string
  914. * @return string
  915. */
  916. function Kbdize($para)
  917. {
  918. if (!isset($this->template_options['desctranslate'])) return $para;
  919. if (!isset($this->template_options['desctranslate']['kbd'])) return $para;
  920. $para = $this->template_options['desctranslate']['kbd'] . $para;
  921. if (!isset($this->template_options['desctranslate']['/kbd'])) return $para;
  922. return $para . $this->template_options['desctranslate']['/kbd'];
  923. }
  924. /**
  925. * Used to convert the contents of <<samp>> in a docblock
  926. * @param string
  927. * @return string
  928. */
  929. function Sampize($para)
  930. {
  931. if (!isset($this->template_options['desctranslate'])) return $para;
  932. if (!isset($this->template_options['desctranslate']['samp'])) return $para;
  933. $para = $this->template_options['desctranslate']['samp'] . $para;
  934. if (!isset($this->template_options['desctranslate']['/samp'])) return $para;
  935. return $para . $this->template_options['desctranslate']['/samp'];
  936. }
  937. /**
  938. * Used to convert <<br>> in a docblock
  939. * @param string
  940. * @return string
  941. */
  942. function Br($para)
  943. {
  944. if (!isset($this->template_options['desctranslate'])) return $para;
  945. if (!isset($this->template_options['desctranslate']['br'])) return $para;
  946. $para = $this->template_options['desctranslate']['br'] . $para;
  947. return $para;
  948. }
  949. /**
  950. * This version does nothing
  951. *
  952. * Perform necessary post-processing of string data. For example, the HTML
  953. * Converters should escape < and > to become &lt; and &gt;
  954. * @return string
  955. */
  956. function postProcess($text)
  957. {
  958. return $text;
  959. }
  960. /**
  961. * Creates a table of contents for a {@}toc} inline tag in a tutorial
  962. *
  963. * This function should return a formatted table of contents. By default, it
  964. * does nothing, it is up to the converter to format the TOC
  965. * @abstract
  966. * @return string table of contents formatted for use in the current output format
  967. * @param array format: array(array('tagname' => section, 'link' => returnsee link, 'id' => anchor name, 'title' => from title tag),...)
  968. */
  969. function formatTutorialTOC($toc)
  970. {
  971. return '';
  972. }
  973. /**
  974. * Write out the formatted source code for a php file
  975. *
  976. * This function provides the primary functionality for the
  977. * {@tutorial tags.filesource.pkg} tag.
  978. * @param string full path to the file
  979. * @param string fully highlighted/linked source code of the file
  980. * @abstract
  981. */
  982. function writeSource($filepath, $source)
  983. {
  984. debug($source);
  985. return;
  986. }
  987. /**
  988. * Write out the formatted source code for an example php file
  989. *
  990. * This function provides the primary functionality for the
  991. * {@tutorial tags.example.pkg} tag.
  992. * @param string example title
  993. * @param string example filename (no path)
  994. * @param string fully highlighted/linked source code of the file
  995. * @abstract
  996. */
  997. function writeExample($title, $path, $source)
  998. {
  999. return;
  1000. }
  1001. /** Translate the path info into a unique file name for the highlighted
  1002. * source code.
  1003. * @param string $pathinfo
  1004. * @return string
  1005. */
  1006. function getFileSourceName($path)
  1007. {
  1008. global $_phpDocumentor_options;
  1009. $pathinfo = $this->proceduralpages->getPathInfo($path, $this);
  1010. $pathinfo['source_loc'] = str_replace($_phpDocumentor_options['Program_Root'].'/','',$pathinfo['source_loc']);
  1011. $pathinfo['source_loc'] = str_replace('/','_',$pathinfo['source_loc']);
  1012. return "fsource_{$pathinfo['package']}_{$pathinfo['subpackage']}_{$pathinfo['source_loc']}";
  1013. }
  1014. /** Return the fixed path to the source-code file folder.
  1015. * @param string $base Path is relative to this folder
  1016. * @return string
  1017. */
  1018. function getFileSourcePath($base)
  1019. {
  1020. if (substr($base, strlen($base) - 1) != PATH_DELIMITER) {
  1021. $base .= PATH_DELIMITER;
  1022. }
  1023. return $base . '__filesource';
  1024. }
  1025. /** Return the path to the current
  1026. * @param string $pathinfo
  1027. * @return string
  1028. */
  1029. function getCurrentPageURL()
  1030. {
  1031. return '{$srcdir}' . PATH_DELIMITER . $this->page_dir;
  1032. }
  1033. /**
  1034. * @return string an output-format dependent link to phpxref-style highlighted
  1035. * source code
  1036. * @abstract
  1037. */
  1038. function getSourceLink($path)
  1039. {
  1040. return '';
  1041. }
  1042. /**
  1043. * @return string Link to the current page being parsed.
  1044. * Should return {@link $curname} and a converter-specific extension.
  1045. * @abstract
  1046. */
  1047. function getCurrentPageLink()
  1048. {
  1049. }
  1050. /**
  1051. * Return a line of highlighted source code with formatted line number
  1052. *
  1053. * If the $path is a full path, then an anchor to the line number will be
  1054. * added as well
  1055. * @param integer line number
  1056. * @param string highlighted source code line
  1057. * @param false|string full path to @filesource file this line is a part of,
  1058. * if this is a single line from a complete file.
  1059. * @return string formatted source code line with line number
  1060. */
  1061. function sourceLine($linenumber, $line, $path = false)
  1062. {
  1063. if ($path)
  1064. {
  1065. return $this->getSourceAnchor($path, $linenumber) .
  1066. $this->Br(sprintf('%-6u',$linenumber).str_replace("\n",'',$line));
  1067. } else
  1068. {
  1069. return $this->Br(sprintf('%-6u',$linenumber).str_replace("\n",'',$line));
  1070. }
  1071. }
  1072. /**
  1073. * Determine whether an element's file has generated source code, used for
  1074. * linking to line numbers of source.
  1075. *
  1076. * Wrapper for {@link $sourcePaths} in this version
  1077. *
  1078. * {@internal since file paths get stored with most/all slashes
  1079. * set to forward slash '/', we need to doublecheck that
  1080. * we're not given a backslashed path to search for...
  1081. * if we are, it's likely that it was originally stored
  1082. * with a forward slash. Further, I'm not convinced it's safe
  1083. * to just check the {@link PHPDOCUMENTOR_WINDOWS} flag, so I'm checking
  1084. * specifically for backslashes intead.}}
  1085. *
  1086. * @param string full path to the source code file
  1087. * @return boolean
  1088. */
  1089. function hasSourceCode($path)
  1090. {
  1091. return isset($this->sourcePaths[$path]);
  1092. if (strpos($path, '\\') > -1) {
  1093. $modifiedPath = str_replace('\\', '/', $path);
  1094. return isset($this->sourcePaths[$modifiedPath]);
  1095. } else {
  1096. return isset($this->sourcePaths[$path]);
  1097. }
  1098. }
  1099. /**
  1100. * Mark a file as having had source code highlighted
  1101. * @param string full path of source file
  1102. */
  1103. function setSourcePaths($path)
  1104. {
  1105. $this->sourcePaths[$path] = true;
  1106. }
  1107. /**
  1108. * Used to translate an XML DocBook entity like &rdquo; from a tutorial by
  1109. * reading the options.ini file for the template.
  1110. * @param string entity name
  1111. */
  1112. function TranslateEntity($name)
  1113. {
  1114. if (!isset($this->template_options['ppage']))
  1115. {
  1116. if (!$this->template_options['preservedocbooktags'])
  1117. return '';
  1118. else
  1119. return '&'.$name.';';
  1120. }
  1121. if (isset($this->template_options['ppage']['&'.$name.';']))
  1122. {
  1123. return $this->template_options['ppage']['&'.$name.';'];
  1124. } else
  1125. {
  1126. if (!$this->template_options['preservedocbooktags'])
  1127. return '';
  1128. else
  1129. return '&'.$name.';';
  1130. }
  1131. }
  1132. /**
  1133. * Used to translate an XML DocBook tag from a tutorial by reading the
  1134. * options.ini file for the template.
  1135. * @param string tag name
  1136. * @param string any attributes Format: array(name => value)
  1137. * @param string the tag contents, if any
  1138. * @param string the tag contents, if any, unpost-processed
  1139. * @return string
  1140. */
  1141. function TranslateTag($name,$attr,$cdata,$unconvertedcdata)
  1142. {
  1143. if (!isset($this->template_options['ppage']))
  1144. {
  1145. if (!$this->template_options['preservedocbooktags'])
  1146. return $cdata;
  1147. else
  1148. return '<'.$name.$this->AttrToString($name,$attr,true).'>'.$cdata.'</'.$name.'>'."\n";
  1149. }
  1150. // make sure this template transforms the tag into something
  1151. if (isset($this->template_options['ppage'][$name]))
  1152. {
  1153. // test for global attribute transforms like $attr$role = class, changing
  1154. // all role="*" attributes to class="*" in html, for example
  1155. foreach($attr as $att => $val)
  1156. {
  1157. if (isset($this->template_options['$attr$'.$att]))
  1158. {
  1159. $new = '';
  1160. if (!isset($this->template_options['$attr$'.$att]['close']))
  1161. {
  1162. $new .= '<'.$this->template_options['$attr$'.$att]['open'];
  1163. if (isset($this->template_options['$attr$'.$att]['cdata!']))
  1164. {
  1165. if (isset($this->template_options['$attr$'.$att]['separateall']))
  1166. $new .= $this->template_options['$attr$'.$att]['separator'];
  1167. else
  1168. $new .= ' ';
  1169. $new .= $this->template_options['$attr$'.$att]['$'.$att];
  1170. $new .= $this->template_options['$attr$'.$att]['separator'];
  1171. if ($this->template_options['$attr$'.$att]['quotevalues']) $val = '"'.$val.'"';
  1172. $new .= $val.'>';
  1173. } else
  1174. {
  1175. $new .= '>'.$val;
  1176. }
  1177. $new .= '</'.$this->template_options['$attr$'.$att]['open'].'>';
  1178. } else
  1179. {
  1180. $new .= $this->template_options['$attr$'.$att]['open'] . $val . $this->template_options['$attr$'.$att]['close'];
  1181. }
  1182. unset($attr[$att]);
  1183. $cdata = $new . $cdata;
  1184. }
  1185. }
  1186. if (!isset($this->template_options['ppage']['/'.$name]))
  1187. {// if the close tag isn't specified, we put opening and closing tags around it, with translated attributes
  1188. if (isset($this->template_options['ppage'][$name.'/']))
  1189. $cdata = '<'.$this->template_options['ppage'][$name].$this->AttrToString($name,$attr).'/>' . $cdata;
  1190. else
  1191. $cdata = '<'.$this->template_options['ppage'][$name].$this->AttrToString($name,$attr).'>' . $cdata .
  1192. '</'.$this->template_options['ppage'][$name].'>';
  1193. } else
  1194. { // if close tag is specified, use the open and close as literal
  1195. if ($name == 'programlisting' && isset($attr['role']) &&
  1196. ($attr['role'] == 'php' || $attr['role'] == 'tutorial' || $attr['role'] == 'html'))
  1197. { // highlight PHP source
  1198. // var_dump($unconvertedcdata, $cdata);exit;
  1199. if ($attr['role'] == 'php') {
  1200. $cdata = $this->ProgramExample($unconvertedcdata, true);
  1201. } elseif ($attr['role'] == 'tutorial') {
  1202. $cdata = $this->TutorialExample($unconvertedcdata);
  1203. } elseif ($attr['role'] == 'html') {
  1204. $cdata = $unconvertedcdata;
  1205. }
  1206. } else
  1207. {// normal case below
  1208. $cdata = $this->template_options['ppage'][$name].$this->AttrToString($name,$attr). $cdata .$this->template_options['ppage']['/'.$name];
  1209. }
  1210. }
  1211. return $cdata;
  1212. } else
  1213. {
  1214. if ($this->template_options['preservedocbooktags'])
  1215. {
  1216. return '<'.$name.$this->AttrToString($name,$attr,true).'>' . $cdata .
  1217. '</'.$name.'>'."\n";
  1218. } else
  1219. {
  1220. return $cdata;
  1221. }
  1222. }
  1223. }
  1224. /**
  1225. * Convert the attribute of a Tutorial docbook tag's attribute list
  1226. * to a string based on the template options.ini
  1227. * @param string tag name
  1228. * @param attribute array
  1229. * @param boolean if true, returns attrname="value"...
  1230. * @return string
  1231. */
  1232. function AttrToString($tag,$attr,$unmodified = false)
  1233. {
  1234. $ret = '';
  1235. if ($unmodified)
  1236. {
  1237. $ret = ' ';
  1238. foreach($attr as $n => $v)
  1239. {
  1240. $ret .= $n.' = "'.$v.'"';
  1241. }
  1242. return $ret;
  1243. }
  1244. // no_attr tells us to ignore all attributes
  1245. if (isset($this->template_options['no_attr'])) return $ret;
  1246. // tagname! tells us to ignore all attributes for this tag
  1247. if (isset($this->template_options['ppage'][$tag.'!'])) return $ret;
  1248. if (count($attr)) $ret = ' ';
  1249. // pass 1, check to see if any attributes add together
  1250. $same = array();
  1251. foreach($attr as $n => $v)
  1252. {
  1253. if (isset($this->template_options['ppage'][$tag.'->'.$n]))
  1254. {
  1255. $same[$this->template_options['ppage'][$tag.'->'.$n]][] = $n;
  1256. }
  1257. }
  1258. foreach($attr as $n => $v)
  1259. {
  1260. if (isset($this->template_options['ppage'][$tag.'->'.$n]))
  1261. {
  1262. if (count($same[$this->template_options['ppage'][$tag.'->'.$n]]) == 1)
  1263. { // only 1 attribute translated for this one
  1264. // this is useful for equivalent value names
  1265. if (isset($this->template_options['ppage'][$tag.'->'.$n.'+'.$v])) $v = $this->template_options['ppage'][$tag.'->'.$n.'+'.$v];
  1266. } else
  1267. { // more than 1 attribute combines to make the new attribute
  1268. $teststrtemp = array();
  1269. foreach($same[$this->template_options['ppage'][$tag.'->'.$n]] as $oldattr)
  1270. {
  1271. $teststrtemp[] = $oldattr.'+'.$attr[$oldattr];
  1272. }
  1273. $teststrs = array();
  1274. $num = count($same[$this->template_options['ppage'][$tag.'->'.$n]]);
  1275. for($i=0;$i<$num;$i++)
  1276. {
  1277. $started = false;
  1278. $a = '';
  1279. for($j=$i;!$started || $j != $i;$j = ($j + $i) % $num)
  1280. {
  1281. if (!empty($a)) $a .= '|';
  1282. $a .= $teststrtemp[$j];
  1283. }
  1284. $teststrs[$i] = $a;
  1285. }
  1286. $done = false;
  1287. foreach($teststrs as $test)
  1288. {
  1289. if ($done) break;
  1290. if (isset($this->template_options['ppage'][$tag.'->'.$test]))
  1291. {
  1292. $done = true;
  1293. $v = $this->template_options['ppage'][$tag.'->'.$test];
  1294. }
  1295. }
  1296. }
  1297. $ret .= $this->template_options['ppage'][$tag.'->'.$n].' = "'.$v.'"';
  1298. } else
  1299. {
  1300. if (!isset($this->template_options['ppage'][$tag.'!'.$n]))
  1301. {
  1302. if (isset($this->template_options['ppage']['$attr$'.$n]))
  1303. $ret .= $this->template_options['ppage']['$attr$'.$n].' = "'.$v.'"';
  1304. else
  1305. $ret .= $n.' = "'.$v.'"';
  1306. }
  1307. }
  1308. }
  1309. return $ret;
  1310. }
  1311. /**
  1312. * Convert the title of a Tutorial docbook tag section
  1313. * to a string based on the template options.ini
  1314. * @param string tag name
  1315. * @param array
  1316. * @param string title text
  1317. * @param string
  1318. * @return string
  1319. */
  1320. function ConvertTitle($tag,$attr,$title,$cdata)
  1321. {
  1322. if (!isset($this->template_options[$tag.'_title'])) return array($attr,$cdata);
  1323. if (isset($this->template_options[$tag.'_title']['tag_attr']))
  1324. {
  1325. $attr[$this->template_options[$tag.'_title']['tag_attr']] = urlencode($cdata);
  1326. $cdata = '';
  1327. } elseif(isset($this->template_options[$tag.'_title']['cdata_start']))
  1328. {
  1329. $cdata = $this->template_options[$tag.'_title']['open'] . $title .
  1330. $this->template_options[$tag.'_title']['close'] . $cdata;
  1331. } else $cdata = $title.$cdata;
  1332. return array($attr,$cdata);
  1333. }
  1334. /**
  1335. * Return a converter-specific id to distinguish tutorials and their
  1336. * sections
  1337. *
  1338. * Used by {@}id}
  1339. * @return string
  1340. */
  1341. function getTutorialId($package,$subpackage,$tutorial,$id)
  1342. {
  1343. return $package.$subpackage.$tutorial.$id;
  1344. }
  1345. /**
  1346. * Create the {@link $elements, $pkg_elements} and {@link $links} arrays
  1347. * @access private
  1348. * @todo version 2.0 - faulty package_output logic should be removed
  1349. *
  1350. * in this version, if the parent file isn't in the package, all
  1351. * the procedural elements are simply shunted to another package!
  1352. */
  1353. function _createPkgElements(&$pages)
  1354. {
  1355. if (empty($this->elements))
  1356. {
  1357. $this->elements = array();
  1358. $this->pkg_elements = array();
  1359. $this->links = array();
  1360. phpDocumentor_out('Building indexes...');
  1361. flush();
  1362. foreach($pages as $j => $flub)
  1363. {
  1364. $this->package = $pages[$j]->parent->package;
  1365. $this->subpackage = $pages[$j]->parent->subpackage;
  1366. $this->class = false;
  1367. $this->curfile = $pages[$j]->parent->getFile();
  1368. $this->curname = $this->getPageName($pages[$j]->parent);
  1369. $this->curpath = $pages[$j]->parent->getPath();
  1370. $use = true;
  1371. if ($this->package_output)
  1372. {
  1373. if (in_array($this->package,$this->package_output))
  1374. {
  1375. $this->addElement($pages[$j]->parent,$pages[$j]);
  1376. } else
  1377. {
  1378. if (count($pages[$j]->classelements))
  1379. {
  1380. list(,$pages[$j]->parent->package) = each($this->package_output);
  1381. reset($this->package_output);
  1382. $pages[$j]->parent->subpackage = '';
  1383. $this->addElement($pages[$j]->parent,$pages[$j]);
  1384. } else
  1385. {
  1386. unset($pages[$j]);
  1387. continue;
  1388. }
  1389. }
  1390. } else
  1391. {
  1392. $this->addElement($pages[$j]->parent,$pages[$j]);
  1393. }
  1394. if ($use)
  1395. for($i=0; $i<count($pages[$j]->elements); $i++)
  1396. {
  1397. $pages[$j]->elements[$i]->docblock->package = $this->package;
  1398. $pages[$j]->elements[$i]->docblock->subpackage = $this->subpackage;
  1399. $this->proceduralpages->replaceElement($pages[$j]->elements[$i]);
  1400. $this->addElement($pages[$j]->elements[$i]);
  1401. }
  1402. for($i=0; $i<count($pages[$j]->classelements); $i++)
  1403. {
  1404. if ($this->class)
  1405. {
  1406. if ($pages[$j]->classelements[$i]->type == 'class')
  1407. {
  1408. if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
  1409. $this->package = $pages[$j]->classelements[$i]->docblock->package;
  1410. if ($this->package_output) if (!in_array($this->package,$this->package_output)) continue;
  1411. $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
  1412. $this->class = $pages[$j]->classelements[$i]->name;
  1413. } else
  1414. {
  1415. if ($this->killclass) continue;
  1416. // force all contained elements to have parent package/subpackage
  1417. $pages[$j]->classelements[$i]->docblock->package = $this->package;
  1418. $pages[$j]->classelements[$i]->docblock->subpackage = $this->subpackage;
  1419. }
  1420. }
  1421. if ($pages[$j]->classelements[$i]->type == 'class')
  1422. {
  1423. if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
  1424. $this->package = $pages[$j]->classelements[$i]->docblock->package;
  1425. if ($this->package_output) if (!in_array($this->package,$this->package_output)) continue;
  1426. $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
  1427. $this->class = $pages[$j]->classelements[$i]->name;
  1428. }
  1429. if (!$this->killclass) $this->addElement($pages[$j]->classelements[$i]);
  1430. }
  1431. }
  1432. phpDocumentor_out("done\n");
  1433. flush();
  1434. }
  1435. $this->sortIndexes();
  1436. $this->sortTodos();
  1437. if ($this->sort_page_contents_by_type) $this->sortPageContentsByElementType($pages);
  1438. }
  1439. /**
  1440. * Process the {@link $tutorials} array
  1441. *
  1442. * Using the tutorialname.ext.ini files, this method sets up tutorial
  1443. * hierarchy. There is some minimal error checking to make sure that no
  1444. * tutorial links to itself, even two levels deep as in tute->next->tute.
  1445. *
  1446. * If all tests pass, it creates the hierarchy
  1447. * @uses generateTutorialOrder()
  1448. * @uses _setupTutorialTree()
  1449. * @access private
  1450. */
  1451. function _processTutorials()
  1452. {
  1453. $parents = $all = array();
  1454. foreach($this->tutorials as $package => $els)
  1455. {
  1456. if ($this->package_output)
  1457. {
  1458. if (!in_array($package,$this->package_output))
  1459. {
  1460. unset($this->tutorials[$package]);
  1461. continue;
  1462. }
  1463. }
  1464. if (!isset($this->pkg_elements[$package]))
  1465. {
  1466. unset($this->tutorials[$package]);
  1467. continue;
  1468. }
  1469. foreach($els as $subpackage => $els2)
  1470. {
  1471. foreach($els2 as $type => $tutorials)
  1472. {
  1473. foreach($tutorials as $tutorial)
  1474. {
  1475. if ($tutorial->ini)
  1476. {
  1477. if (isset($tutorial->ini['Linked Tutorials']))
  1478. {
  1479. foreach($tutorial->ini['Linked Tutorials'] as $child)
  1480. {
  1481. $sub = (empty($tutorial->subpackage) ? '' : $tutorial->subpackage . '/');
  1482. $kid = $tutorial->package . '/' . $sub . $child . '.' . $tutorial->tutorial_type;
  1483. // parent includes self as a linked tutorial?
  1484. $kidlink = $this->getTutorialLink($kid,false,false,array($tutorial->package));
  1485. if (is_object($kidlink) && $this->returnSee($kidlink) == $tutorial->getLink($this))
  1486. { // bad!
  1487. addErrorDie(PDERROR_TUTORIAL_IS_OWN_CHILD,$tutorial->name,$tutorial->name.'.ini');
  1488. }
  1489. }
  1490. $parents[] = $tutorial;
  1491. }
  1492. }
  1493. $all[$package][$subpackage][$type][] = $tutorial;
  1494. }
  1495. }
  1496. }
  1497. }
  1498. // loop error-checking, use this to eliminate possibility of accidentally linking to a parent as a child
  1499. $testlinks = array();
  1500. foreach($parents as $parent)
  1501. {
  1502. $testlinks[$parent->name]['links'][] = $parent->getLink($this);
  1503. $testlinks[$parent->name]['name'][$parent->getLink($this)] = $parent->name;
  1504. }
  1505. // generate the order of tutorials, and link them together
  1506. foreach($parents as $parent)
  1507. {
  1508. foreach($parent->ini['Linked Tutorials'] as $child)
  1509. {
  1510. $sub = (empty($parent->subpackage) ? '' : $parent->subpackage . '/');
  1511. $kid = $parent->package . '/' . $sub . $child . '.' . $parent->tutorial_type;
  1512. // child tutorials must be in the same package AND subpackage
  1513. // AND have the same extension as the parent, makes things clearer for both ends
  1514. if (in_array($this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package))),$testlinks[$parent->name]['links']))
  1515. 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');
  1516. if ($this->returnSee($this->getTutorialLink($kid,false,false,array($parent->package))) == $kid)
  1517. {
  1518. addWarning(PDERROR_CHILD_TUTORIAL_NOT_FOUND, $child . '.' . $parent->tutorial_type, $parent->name .'.ini',$parent->package, $parent->subpackage);
  1519. }
  1520. }
  1521. }
  1522. $new = $tree = $roots = array();
  1523. // build a list of all 'root' tutorials (tutorials without parents).
  1524. foreach($parents as $i => $parent)
  1525. {
  1526. if (! $parent->isChildOf($parents)) {
  1527. $roots[] = $parent;
  1528. }
  1529. }
  1530. $parents = $roots;
  1531. // add the parents and all child tutorials in order to the list of tutorials to process
  1532. foreach($parents as $parent)
  1533. {
  1534. $this->generateTutorialOrder($parent,$all,$new);
  1535. }
  1536. if (count($all))
  1537. {
  1538. // add the leftover tutorials
  1539. foreach($all as $package => $els)
  1540. {
  1541. foreach($els as $subpackage => $els2)
  1542. {
  1543. foreach($els2 as $type => $tutorials)
  1544. {
  1545. foreach($tutorials as $tutorial)
  1546. {
  1547. $new[$package][$subpackage][$type][] = $tutorial;
  1548. }
  1549. }
  1550. }
  1551. }
  1552. }
  1553. // remove the old, unprocessed tutorials, and set it up with the next code
  1554. $this->tutorials = array();
  1555. // reset integrity of the tutorial list
  1556. $prev = false;
  1557. uksort($new, 'tutorialcmp');
  1558. // debug($this->vardump_tree($new));exit;
  1559. foreach($new as $package => $els)
  1560. {
  1561. foreach($els as $subpackage => $els2)
  1562. {
  1563. foreach($els2 as $type => $tutorials)
  1564. {
  1565. foreach($tutorials as $tutorial)
  1566. {
  1567. if ($prev)
  1568. {
  1569. $this->tutorials[$prevpackage][$prevsubpackage][$prevtype][$prevname]->setNext($tutorial,$this);
  1570. $tutorial->setPrev($prev,$this);
  1571. }
  1572. $this->tutorials[$package][$subpackage][$type][$tutorial->name] = $tutorial;
  1573. $prev = $tutorial->getLink($this,true);
  1574. $prevpackage = $package;
  1575. $prevsubpackage = $subpackage;
  1576. $prevtype = $type;
  1577. $prevname = $tutorial->name;
  1578. }
  1579. }
  1580. }
  1581. }
  1582. $this->tutorial_tree = $this->_setupTutorialTree();
  1583. return $new;
  1584. }
  1585. /**
  1586. * called by {@link phpDocumentor_IntermediateParser::Convert()} to traverse
  1587. * the array of pages and their elements, converting them to the output format
  1588. *
  1589. * The walk() method should be flexible enough such that it never needs
  1590. * modification. walk() sets up all of the indexes, and sorts everything in
  1591. * logical alphabetical order. It then passes each element individually to
  1592. * {@link Convert()}, which then passes to the Convert*() methods. A child
  1593. * Converter need not override any of these unless special functionality must
  1594. * be added. see {@tutorial Converters/template.vars.cls} for details.
  1595. * {@internal
  1596. * walk() first creates all of the indexes {@link $elements, $pkg_elements}
  1597. * and the left indexes specified by {@link $leftindexes},
  1598. * and then sorts them by calling {@link sortIndexes()}.
  1599. *
  1600. * Next, it converts all README/CHANGELOG/INSTALL-style files, using
  1601. * {@link Convert_RIC}.
  1602. *
  1603. * After this, it
  1604. * passes all package-level docs to Convert(). Then, it calls the index
  1605. * sorting functions {@link formatPkgIndex(), formatIndex()} and
  1606. * {@link formatLeftIndex()}.
  1607. *
  1608. * Finally, it converts each procedural page in alphabetical order. This
  1609. * stage passes elements from the physical file to Convert() in alphabetical
  1610. * order. First, procedural page elements {@link parserDefine, parserInclude}
  1611. * {@link parserGlobal}, and {@link parserFunction} are passed to Convert().
  1612. *
  1613. * Then, class elements are passed in this order: {@link parserClass}, then
  1614. * all of the {@link parserVar}s in the class and all of the
  1615. * {@link parserMethod}s in the class. Classes are in alphabetical order,
  1616. * and both vars and methods are in alphabetical order.
  1617. *
  1618. * Finally, {@link ConvertErrorLog()} is called and the data walk is complete.}}
  1619. * @param array Format: array(fullpath => {@link parserData} structure with full {@link parserData::$elements}
  1620. * and {@link parserData::$class_elements}.
  1621. * @param array Format: array({@link parserPackagePage} 1, {@link parserPackagePage} 2,...)
  1622. * @uses Converter::_createPkgElements() sets up {@link $elements} and
  1623. * {@link $pkg_elements} array, as well as {@link $links}
  1624. */
  1625. function walk(&$pages,&$package_pages)
  1626. {
  1627. if (empty($pages))
  1628. {
  1629. die("<b>ERROR</b>: nothing parsed");
  1630. }
  1631. $this->_createPkgElements($pages);
  1632. if (count($this->ric))
  1633. {
  1634. phpDocumentor_out("Converting README/INSTALL/CHANGELOG contents...\n");
  1635. flush();
  1636. foreach($this->ric as $name => $contents)
  1637. {
  1638. phpDocumentor_out("$name...");
  1639. flush();
  1640. $this->Convert_RIC($name,$contents);
  1641. }
  1642. phpDocumentor_out("\ndone\n");
  1643. flush();
  1644. }
  1645. foreach($package_pages as $i => $perp)
  1646. {
  1647. if ($this->package_output)
  1648. {
  1649. if (!in_array($package_pages[$i]->package,$this->package_output)) continue;
  1650. }
  1651. phpDocumentor_out('Converting package page for package '.$package_pages[$i]->package.'... ');
  1652. flush();
  1653. $this->package = $package_pages[$i]->package;
  1654. $this->subpackage = '';
  1655. $this->class = false;
  1656. $this->Convert($package_pages[$i]);
  1657. phpDocumentor_out("done\n");
  1658. flush();
  1659. }
  1660. phpDocumentor_out("Converting tutorials/extended docs\n");
  1661. flush();
  1662. // get tutorials into the order they will display, and set next/prev links
  1663. $new = $this->_processTutorials();
  1664. foreach($this->tutorials as $package => $els)
  1665. {
  1666. foreach($els as $subpackage => $els2)
  1667. {
  1668. foreach($els2 as $type => $tutorials)
  1669. {
  1670. foreach($tutorials as $tutorial)
  1671. {
  1672. switch ($type)
  1673. {
  1674. case 'pkg' :
  1675. $a = '';
  1676. if ($tutorial->ini)
  1677. $a .= 'Top-level ';
  1678. if (!empty($tutorial->subpackage))
  1679. $a .= 'Sub-';
  1680. $ptext = "Converting ${a}Package-level tutorial ".$tutorial->name.'...';
  1681. break;
  1682. case 'cls' :
  1683. $a = '';
  1684. if ($tutorial->ini)
  1685. $a .= 'Top-level ';
  1686. $ptext = "Converting ${a}Class-level tutorial " . $tutorial->name ." and associating...";
  1687. $link = Converter::getClassLink(str_replace('.cls','',$tutorial->name), $tutorial->package);
  1688. if (is_object($link))
  1689. {
  1690. if ($this->sort_absolutely_everything)
  1691. {
  1692. $addend = 'unsuccessful ';
  1693. if (isset($this->package_elements[$tutorial->package][$tutorial->subpackage]['class'][$link->name]))
  1694. {
  1695. $this->package_elements[$tutorial->package][$tutorial->subpackage]['class'][$link->name][0]->addTutorial($tutorial,$this);
  1696. $addend = 'success ';
  1697. }
  1698. } else
  1699. {
  1700. $addend = 'unsuccessful ';
  1701. if (!isset($this->classes->killclass[str_replace('.cls','',$tutorial->name)]) && !isset($this->classes->killclass[str_replace('.cls','',$tutorial->name)][$tutorial->path]))
  1702. {
  1703. foreach($pages as $j => $inf)
  1704. {
  1705. foreach($inf->classelements as $i => $class)
  1706. {
  1707. if ($class->type == 'class' && $class->name == str_replace('.cls','',$tutorial->name) && $class->path == $link->path)
  1708. {
  1709. $pages[$j]->classelements[$i]->addTutorial($tutorial,$this);
  1710. $addend = 'success ';
  1711. }
  1712. }
  1713. }
  1714. }
  1715. }
  1716. $ptext .= $addend;
  1717. } else $ptext .= "unsuccessful ";
  1718. break;
  1719. case 'proc' :
  1720. $a = '';
  1721. if ($tutorial->ini)
  1722. $a .= 'Top-level ';
  1723. $ptext = "Converting ${a}Procedural-level tutorial ".$tutorial->name." and associating...";
  1724. $link = Converter::getPageLink(str_replace('.proc','',$tutorial->name), $tutorial->package);
  1725. if (is_object($link))
  1726. {
  1727. $addend = 'unsuccessful ';
  1728. if ($this->sort_absolutely_everything)
  1729. {
  1730. if (isset($this->package_elements[$tutorial->package][$tutorial->subpackage]['page'][$link->path]))
  1731. {
  1732. $this->package_elements[$tutorial->package][$tutorial->subpackage]['page'][$link->path][0]->addTutorial($tutorial,$this);
  1733. $addend = "success ";
  1734. }
  1735. } else
  1736. {
  1737. foreach($pages as $j => $info)
  1738. {
  1739. if ($j == $link->path)
  1740. {
  1741. $pages[$j]->addTutorial($tutorial,$this);
  1742. $addend = "success ";
  1743. }
  1744. }
  1745. }
  1746. $ptext .= $addend;
  1747. } else $ptext .= "unsuccessful ";
  1748. break;
  1749. }
  1750. phpDocumentor_out($ptext);
  1751. flush();
  1752. $this->package = $tutorial->package;
  1753. $this->subpackage = $tutorial->subpackage;
  1754. $this->Convert($tutorial);
  1755. phpDocumentor_out("done\n");
  1756. flush();
  1757. }
  1758. }
  1759. }
  1760. }
  1761. phpDocumentor_out("Formatting Package Indexes...");
  1762. flush();
  1763. $this->formatPkgIndex();
  1764. phpDocumentor_out("done\n");
  1765. flush();
  1766. phpDocumentor_out("Formatting Index...");
  1767. flush();
  1768. $this->formatIndex();
  1769. phpDocumentor_out("done\n\n");
  1770. flush();
  1771. phpDocumentor_out("Formatting Left Quick Index...");
  1772. flush();
  1773. $this->formatLeftIndex();
  1774. phpDocumentor_out("done\n\n");
  1775. flush();
  1776. if ($this->sort_absolutely_everything) return $this->walk_everything();
  1777. foreach($pages as $j => $flub)
  1778. {
  1779. phpDocumentor_out('Converting '.$pages[$j]->parent->getPath());
  1780. flush();
  1781. $this->package = $pages[$j]->parent->package;
  1782. $this->subpackage = $pages[$j]->parent->subpackage;
  1783. $this->class = false;
  1784. $this->curfile = $pages[$j]->parent->getFile();
  1785. $this->curname = $this->getPageName($pages[$j]->parent);
  1786. $this->curpath = $pages[$j]->parent->getPath();
  1787. $use = true;
  1788. if ($this->package_output)
  1789. {
  1790. if (in_array($this->package,$this->package_output))
  1791. {
  1792. $this->Convert($pages[$j]);
  1793. } else
  1794. {
  1795. $use = false;
  1796. }
  1797. } else
  1798. {
  1799. $this->Convert($pages[$j]);
  1800. }
  1801. phpDocumentor_out(" Procedural Page Elements...");
  1802. flush();
  1803. if ($use)
  1804. for($i=0; $i<count($pages[$j]->elements); $i++)
  1805. {
  1806. $a = $pages[$j]->elements[$i]->docblock->getKeyword('access');
  1807. if (is_object($a)) $a = $a->getString();
  1808. if (!$this->parseprivate && ($a == 'private'))
  1809. continue;
  1810. // phpDocumentor_out(" ".$pages[$j]->elements[$i]->name."\n");
  1811. $pages[$j]->elements[$i]->docblock->package = $this->package;
  1812. $pages[$j]->elements[$i]->docblock->subpackage = $this->subpackage;
  1813. $this->Convert($pages[$j]->elements[$i]);
  1814. }
  1815. phpDocumentor_out(" Classes...");
  1816. $this->class = false;
  1817. flush();
  1818. for($i=0; $i<count($pages[$j]->classelements); $i++)
  1819. {
  1820. if ($this->class)
  1821. {
  1822. if ($pages[$j]->classelements[$i]->type == 'class')
  1823. {
  1824. if (!$this->killclass) $this->endClass();
  1825. $this->killclass = false;
  1826. if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
  1827. $this->package = $pages[$j]->classelements[$i]->docblock->package;
  1828. if ($this->package_output) if (!in_array($this->package,$this->package_output)) continue;
  1829. $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
  1830. $this->class = $pages[$j]->classelements[$i]->name;
  1831. } else
  1832. {
  1833. $a = $pages[$j]->classelements[$i]->docblock->getKeyword('access');
  1834. if (is_object($a)) $a = $a->getString();
  1835. if (!$this->parseprivate && ($a == 'private'))
  1836. continue;
  1837. if ($this->killclass) continue;
  1838. // force all contained elements to have parent package/subpackage
  1839. $pages[$j]->classelements[$i]->docblock->package = $this->package;
  1840. $pages[$j]->classelements[$i]->docblock->subpackage = $this->subpackage;
  1841. }
  1842. }
  1843. if ($pages[$j]->classelements[$i]->type == 'class')
  1844. {
  1845. $this->killclass = false;
  1846. if ($this->checkKillClass($pages[$j]->classelements[$i]->getName(),$pages[$j]->classelements[$i]->getPath())) continue;
  1847. $this->package = $pages[$j]->classelements[$i]->docblock->package;
  1848. if ($this->package_output) if (!in_array($this->package,$this->package_output)) continue;
  1849. $this->subpackage = $pages[$j]->classelements[$i]->docblock->subpackage;
  1850. $this->class = $pages[$j]->classelements[$i]->name;
  1851. }
  1852. if ($this->killclass) continue;
  1853. // phpDocumentor_out(" ".$pages[$j]->classelements[$i]->name."\n");
  1854. $this->Convert($pages[$j]->classelements[$i]);
  1855. }
  1856. if (count($pages[$j]->classelements) && !$this->killclass) $this->endClass();
  1857. phpDocumentor_out(" done\n");
  1858. flush();
  1859. $this->endPage();
  1860. }
  1861. phpDocumentor_out("\nConverting @todo List...");
  1862. flush();
  1863. if (count($this->todoList))
  1864. {
  1865. $this->ConvertTodoList();
  1866. }
  1867. phpDocumentor_out("done\n");
  1868. flush();
  1869. phpDocumentor_out("\nConverting Error Log...");
  1870. flush();
  1871. $this->ConvertErrorLog();
  1872. phpDocumentor_out("done\n");
  1873. flush();
  1874. }
  1875. /**
  1876. * Get a tree structure representing the hierarchy of tutorials
  1877. *
  1878. * Returns an array in format:
  1879. * <pre>
  1880. * array('tutorial' => {@link parserTutorial},
  1881. * 'kids' => array( // child tutorials
  1882. * array('tutorial' => child {@link parserTutorial},
  1883. * 'kids' => array(...)
  1884. * )
  1885. * )
  1886. * )
  1887. * </pre>
  1888. * @param parserTutorial|array
  1889. * @tutorial tutorials.pkg
  1890. * @return array
  1891. */
  1892. function getTutorialTree($tutorial)
  1893. {
  1894. if (is_object($tutorial))
  1895. {
  1896. $path = $this->_tutorial_path($tutorial,$tutorial,$tutorial);
  1897. if (isset($this->tutorial_tree[$path])) {
  1898. $tutorial = $this->tutorial_tree[$path];
  1899. } else {
  1900. return false;
  1901. }
  1902. }
  1903. $tree = array();
  1904. if (isset($tutorial['tutorial']))
  1905. {
  1906. $tree['tutorial'] = $tutorial['tutorial'];
  1907. if (isset($tutorial['child']))
  1908. {
  1909. foreach($tutorial['child'] as $a => $b)
  1910. {
  1911. $btut = $b['tutorial'];
  1912. $res['tutorial'] = $this->tutorials[$btut->package][$btut->subpackage][$btut->tutorial_type][$btut->name];
  1913. if (isset($b['child']))
  1914. {
  1915. $tempres = Converter::getTutorialTree($b);
  1916. $res['kids'] = $tempres['kids'];
  1917. }
  1918. $tree['kids'][] = $res;
  1919. }
  1920. }
  1921. }
  1922. return $tree;
  1923. }
  1924. /**
  1925. * Remove tutorials one by one from $all, and transfer them into $new in the
  1926. * order they should be parsed
  1927. * @param parserTutorial
  1928. * @param array
  1929. * @param array
  1930. * @access private
  1931. */
  1932. function generateTutorialOrder($parent,&$all,&$new)
  1933. {
  1934. // remove from the list of tutorials to process
  1935. foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_type] as $ind => $t)
  1936. {
  1937. if ($t->name == $parent->name) {
  1938. unset($all[$parent->package][$parent->subpackage][$parent->tutorial_type][$ind]);
  1939. }
  1940. }
  1941. // add to the new ordered list of tutorials
  1942. $x = &$new[$parent->package][$parent->subpackage][$parent->tutorial_type];
  1943. if (!is_object($x[count($x) - 1]) || $x[count($x) - 1]->name != $parent->name)
  1944. { // only add if the parent isn't also a child
  1945. $new[$parent->package][$parent->subpackage][$parent->tutorial_type][] = $parent;
  1946. // add a new branch to the tree
  1947. }
  1948. // process all child tutorials, and insert them in order
  1949. // debug("processing parent ".$parent->name);
  1950. if ($parent->ini)
  1951. {
  1952. foreach($parent->ini['Linked Tutorials'] as $child)
  1953. {
  1954. $sub = (empty($parent->subpackage) ? '' : $parent->subpackage . '/');
  1955. $kid = $parent->package . '/' . $sub . $child . '.' . $parent->tutorial_type;
  1956. $_klink = $this->getTutorialLink($kid,false,false,array($parent->package));
  1957. if (is_object($_klink)) {
  1958. $klink = $this->returnSee($_klink);
  1959. } else {
  1960. $klink = false;
  1961. }
  1962. // remove the child from the list of remaining tutorials
  1963. foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_type] as $ind => $tute)
  1964. {
  1965. if ($klink && $tute->getLink($this) == $klink)
  1966. {
  1967. // set up parent, next and prev links
  1968. $tute->setParent($parent, $this);
  1969. // remove the child from the list of tutorials to process
  1970. foreach($all[$parent->package][$parent->subpackage][$parent->tutorial_type] as $ind => $t)
  1971. {
  1972. if ($t->name == $tute->name)
  1973. unset($all[$parent->package][$parent->subpackage][$parent->tutorial_type][$ind]);
  1974. }
  1975. // add to the new ordered list of tutorials
  1976. $new[$parent->package][$parent->subpackage][$parent->tutorial_type][] = $tute;
  1977. if ($tute->ini)
  1978. {
  1979. // add all the child's child tutorials to the list
  1980. $this->generateTutorialOrder($tute,$all,$new);
  1981. }
  1982. }
  1983. }
  1984. }
  1985. }
  1986. return;
  1987. }
  1988. /** Returns the path to this tutorial as a string
  1989. * @param parserTutorial $pkg
  1990. * @param parserTutorial $subpkg
  1991. * @param parserTutorial $namepkg
  1992. * @return string */
  1993. function _tutorial_path($pkg, $subpkg = 0, $namepkg = 0)
  1994. {
  1995. if (!$subpkg) {
  1996. $subpkg = $pkg;
  1997. }
  1998. if (!$namepkg) {
  1999. $namepkg = $pkg;
  2000. }
  2001. $subpackagename = ($subpkg->subpackage ? '/' . $subpkg->subpackage : '');
  2002. return $pkg->package . $subpackagename . '/' . $namepkg->name;
  2003. }
  2004. /**
  2005. * Creates a tree structure of tutorials
  2006. *
  2007. * Format:
  2008. * <pre>
  2009. * array('package/subpackage/tutorial1.ext' =>
  2010. * array('tutorial' => {@link parserTutorial},
  2011. * 'child' =>
  2012. * array('package/subpackage/child1tutorial.ext' => ...,
  2013. * 'package/subpackage/child2tutorial.ext' => ...,
  2014. * ...
  2015. * )
  2016. * 'package/subpackage/tutorial2.ext' => ...,
  2017. * ...
  2018. * )
  2019. * </pre>
  2020. * @return array the tutorial tree
  2021. * @access private
  2022. */
  2023. function _setupTutorialTree($parent = false)
  2024. {
  2025. if (! isset($this->processed_tutorials)) {
  2026. $this->processed_tutorials = array();
  2027. }
  2028. $tree = array();
  2029. if (!$parent)
  2030. {
  2031. foreach($this->tutorials as $package => $s)
  2032. {
  2033. foreach($s as $subpackage => $t)
  2034. {
  2035. foreach($t as $type => $n)
  2036. {
  2037. foreach($n as $name => $tutorial)
  2038. {
  2039. if ($tutorial->parent) {
  2040. continue;
  2041. }
  2042. $child_path = $this->_tutorial_path($tutorial,$tutorial,$tutorial);
  2043. if (isset($this->processed_tutorials[$child_path])) {
  2044. continue;
  2045. }
  2046. $this->processed_tutorials[$child_path] = $tutorial;
  2047. //debug("parent ".$tutorial->name);
  2048. $ret = $this->_setupTutorialTree($tutorial);
  2049. if (!count($tree)) {
  2050. $tree = $ret;
  2051. } else {
  2052. $tree = array_merge($tree,$ret);
  2053. }
  2054. }
  2055. }
  2056. }
  2057. }
  2058. return $tree;
  2059. }
  2060. $parent_path = $this->_tutorial_path($parent);
  2061. $tree[$parent_path]['tutorial'] = $parent;
  2062. // process all child tutorials, and insert them in order
  2063. if ($parent->ini)
  2064. {
  2065. foreach($parent->ini['Linked Tutorials'] as $child)
  2066. {
  2067. if (isset($this->tutorials[$parent->package][$parent->subpackage]
  2068. [$parent->tutorial_type][$child . '.' .
  2069. $parent->tutorial_type])) {
  2070. // remove the child from the list of remaining tutorials
  2071. $tute = $this->tutorials[$parent->package][$parent->subpackage]
  2072. [$parent->tutorial_type][$child . '.' .
  2073. $parent->tutorial_type];
  2074. } else {
  2075. $tute = false;
  2076. }
  2077. if (!$tute) {
  2078. continue;
  2079. }
  2080. $child_path = $this->_tutorial_path($parent,$parent,$tute);
  2081. if (isset($this->processed_tutorials[$child_path])) {
  2082. continue;
  2083. }
  2084. $this->processed_tutorials[$child_path] = $tute;
  2085. if ($tute->name != $child . '.' . $parent->tutorial_type) {
  2086. continue;
  2087. }
  2088. //echo "Adding [$child_path] to [$parent_path]<br>";
  2089. $tree[$parent_path]['child'][$this->_tutorial_path($parent,$parent,$tute)]['tutorial']
  2090. = $tute;
  2091. if (!$tute->ini) {
  2092. continue;
  2093. }
  2094. // add all the child's child tutorials to the list
  2095. if (!isset($tree[$parent_path]['child'])) {
  2096. $tree[$parent_path]['child'] = $this->_setupTutorialTree($tute);
  2097. } else {
  2098. $tree[$parent_path]['child'] = array_merge($tree[$parent_path]['child'],
  2099. $this->_setupTutorialTree($tute));
  2100. }
  2101. }
  2102. }
  2103. return $tree;
  2104. }
  2105. /**
  2106. * Debugging function for dumping {@link $tutorial_tree}
  2107. * @return string
  2108. */
  2109. function vardump_tree($tree,$indent='')
  2110. {
  2111. if (phpDocumentor_get_class($tree) == 'parsertutorial') return $tree->name.' extends '.($tree->parent? $tree->parent->name : 'nothing');
  2112. $a = '';
  2113. foreach($tree as $ind => $stuff)
  2114. {
  2115. $x = $this->vardump_tree($stuff,"$indent ");
  2116. $a .= $indent.'['.$ind." => \n ".$indent.$x."]\n";
  2117. }
  2118. return substr($a,0,strlen($a) - 1);
  2119. }
  2120. /**
  2121. * @access private
  2122. */
  2123. function sort_package_elements($a,$b)
  2124. {
  2125. if (($a->type == $b->type) && (isset($a->isConstructor) && $a->isConstructor)) return -1;
  2126. if (($a->type == $b->type) && (isset($b->isConstructor) && $b->isConstructor)) return 1;
  2127. if ($a->type == $b->type) return strnatcasecmp($a->name,$b->name);
  2128. if ($a->type == 'class') return -1;
  2129. if ($b->type == 'class') return 1;
  2130. if ($a->type == 'const') return -1;
  2131. if ($b->type == 'const') return 1;
  2132. if ($a->type == 'var') return -1;
  2133. if ($b->type == 'var') return 1;
  2134. if ($a->type == 'page') return -1;
  2135. if ($b->type == 'page') return 1;
  2136. if ($a->type == 'include') return -1;
  2137. if ($b->type == 'include') return 1;
  2138. if ($a->type == 'define') return -1;
  2139. if ($b->type == 'define') return 1;
  2140. if ($a->type == 'global') return -1;
  2141. if ($b->type == 'global') return 1;
  2142. if ($a->type == 'function') return -1;
  2143. if ($b->type == 'function') return 1;
  2144. }
  2145. /**
  2146. * @access private
  2147. */
  2148. function defpackagesort($a,$b)
  2149. {
  2150. if ($a == $GLOBALS['phpDocumentor_DefaultPackageName']) return -1;
  2151. if ($b == $GLOBALS['phpDocumentor_DefaultPackageName']) return 0;
  2152. return strnatcasecmp($a,$b);
  2153. }
  2154. /**
  2155. * @access private
  2156. */
  2157. function Pc_sort($a,$b)
  2158. {
  2159. return strnatcasecmp(key($a),key($b));
  2160. }
  2161. /**
  2162. * walk over elements by package rather than page
  2163. *
  2164. * This method is designed for converters like the PDF converter that need
  2165. * everything passed in alphabetical order by package/subpackage and by
  2166. * procedural and then class information
  2167. * @see PDFdefaultConverter
  2168. * @see walk()
  2169. */
  2170. function walk_everything()
  2171. {
  2172. global $hooser;
  2173. $hooser = false;
  2174. uksort($this->package_elements,array($this,'defpackagesort'));
  2175. foreach($this->package_elements as $package => $r)
  2176. {
  2177. if ($this->package_output)
  2178. {
  2179. if (!in_array($this->package,$this->package_output))
  2180. {
  2181. unset($this->package_elements[$package]);
  2182. continue;
  2183. }
  2184. }
  2185. uksort($this->package_elements[$package],'strnatcasecmp');
  2186. }
  2187. foreach($this->package_elements as $package => $r)
  2188. {
  2189. foreach($this->package_elements[$package] as $subpackage => $r)
  2190. {
  2191. if (isset($r['page']))
  2192. {
  2193. uksort($r['page'],'strnatcasecmp');
  2194. foreach($r['page'] as $page => $oo)
  2195. {
  2196. usort($this->package_elements[$package][$subpackage]['page'][$page],array($this,'sort_package_elements'));
  2197. }
  2198. }
  2199. if (isset($r['class']))
  2200. {
  2201. uksort($r['class'],'strnatcasecmp');
  2202. foreach($r['class'] as $page => $oo)
  2203. {
  2204. usort($r['class'][$page],array($this,'sort_package_elements'));
  2205. }
  2206. }
  2207. $this->package_elements[$package][$subpackage] = $r;
  2208. }
  2209. }
  2210. foreach($this->package_elements as $package => $s)
  2211. {
  2212. $notyet = false;
  2213. foreach($s as $subpackage => $r)
  2214. {
  2215. $this->package = $package;
  2216. $this->subpackage = $subpackage;
  2217. if (isset($r['page']))
  2218. {
  2219. $this->class = false;
  2220. foreach($r['page'] as $page => $elements)
  2221. {
  2222. if (is_array($elements))
  2223. {
  2224. foreach($elements as $element)
  2225. {
  2226. if ($element->type == 'page')
  2227. {
  2228. phpDocumentor_out('Converting '.$element->parent->getPath());
  2229. flush();
  2230. $this->curfile = $element->parent->getFile();
  2231. $this->curname = $this->getPageName($element->parent);
  2232. $this->curpath = $element->parent->getPath();
  2233. $notyet = true;
  2234. } else
  2235. {
  2236. // force all contained elements to have parent package/subpackage
  2237. $element->docblock->package = $this->package;
  2238. $element->docblock->subpackage = $this->subpackage;
  2239. $a = $element->docblock->getKeyword('access');
  2240. if (is_object($a)) $a = $a->getString();
  2241. if (!$this->parseprivate && ($a == 'private'))
  2242. continue;
  2243. }
  2244. if ($notyet)
  2245. {
  2246. phpDocumentor_out(" Procedural Page Elements...");
  2247. flush();
  2248. $notyet = false;
  2249. }
  2250. $this->Convert($element);
  2251. }
  2252. }
  2253. $this->endPage();
  2254. phpDocumentor_out("done\n");
  2255. flush();
  2256. }
  2257. }
  2258. $start_classes = true;
  2259. if (isset($r['class']))
  2260. {
  2261. foreach($r['class'] as $class => $elements)
  2262. {
  2263. foreach($elements as $element)
  2264. {
  2265. if ($element->type == 'class')
  2266. {
  2267. if (!$start_classes)
  2268. {
  2269. if (count($elements) && !$this->killclass) $this->endClass();
  2270. phpDocumentor_out("done\n");
  2271. flush();
  2272. }
  2273. $start_classes = false;
  2274. $this->class = $element->getName();
  2275. $this->killclass = false;
  2276. if ($this->checkKillClass($element->getName(),$element->getPath())) continue;
  2277. if (!$this->killclass)
  2278. {
  2279. phpDocumentor_out('Converting '.$this->class."...");
  2280. flush();
  2281. $notyet = true;
  2282. }
  2283. } else
  2284. {
  2285. if ($notyet)
  2286. {
  2287. phpDocumentor_out("Variables/methods/Class constants...\n");
  2288. flush();
  2289. $notyet = false;
  2290. }
  2291. $a = $element->docblock->getKeyword('access');
  2292. if (is_object($a)) $a = $a->getString();
  2293. if (!$this->parseprivate && ($a == 'private'))
  2294. continue;
  2295. if ($this->killclass) continue;
  2296. // force all contained elements to have parent package/subpackage
  2297. $element->docblock->package = $this->package;
  2298. $element->docblock->subpackage = $this->subpackage;
  2299. }
  2300. if ($this->killclass) continue;
  2301. $this->Convert($element);
  2302. }
  2303. }
  2304. if (count($elements) && !$this->killclass) $this->endClass();
  2305. phpDocumentor_out("done\n");
  2306. flush();
  2307. } // if isset($r['class'])
  2308. } // foreach($s
  2309. } // foreach($this->package_elements)
  2310. phpDocumentor_out("\nConverting @todo List...");
  2311. flush();
  2312. if (count($this->todoList))
  2313. {
  2314. $this->ConvertTodoList();
  2315. }
  2316. phpDocumentor_out("done\n");
  2317. flush();
  2318. phpDocumentor_out("\nConverting Error Log...");
  2319. flush();
  2320. $this->ConvertErrorLog();
  2321. phpDocumentor_out("done\n");
  2322. flush();
  2323. }
  2324. /**
  2325. * Convert the phpDocumentor parsing/conversion error log
  2326. * @abstract
  2327. */
  2328. function ConvertErrorLog()
  2329. {
  2330. }
  2331. /**
  2332. * Convert the list of all @todo tags
  2333. * @abstract
  2334. */
  2335. function ConvertTodoList()
  2336. {
  2337. }
  2338. /**
  2339. * Sorts the @todo list - do not override or modify this function
  2340. * @access private
  2341. * @uses _sortTodos passed to {@link usort()} to sort the todo list
  2342. */
  2343. function sortTodos()
  2344. {
  2345. phpDocumentor_out("\nSorting @todo list...");
  2346. flush();
  2347. foreach($this->todoList as $package => $r) {
  2348. usort($this->todoList[$package], array('Converter', '_sortTodoPackage'));
  2349. foreach ($r as $a => $sub) {
  2350. if (is_array($this->todoList[$package][$a][1])) {
  2351. usort($this->todoList[$package][$a][1],array('Converter', '_sortTodos'));
  2352. }
  2353. }
  2354. }
  2355. phpDocumentor_out("done\n");
  2356. }
  2357. /** @access private */
  2358. function _sortTodoPackage($a, $b)
  2359. {
  2360. return strnatcasecmp($a[0]->name, $b[0]->name);
  2361. }
  2362. /** @access private */
  2363. function _sortTodos($a, $b)
  2364. {
  2365. if (!is_object($a)) {
  2366. var_dump($a);
  2367. }
  2368. return strnatcasecmp($a->getString(), $b->getString());
  2369. }
  2370. /**
  2371. * Sorts all indexes - do not override or modify this function
  2372. * @uses $leftindex based on the value of leftindex, sorts link arrays
  2373. * @uses $class_elements sorts with {@link compareLink}
  2374. * @uses $page_elements sorts with {@link compareLink}
  2375. * @uses $define_elements sorts with {@link compareLink}
  2376. * @uses $global_elements sorts with {@link compareLink}
  2377. * @uses $function_elements sorts with {@link compareLink}
  2378. * @uses $elements sorts with {@link elementCmp}
  2379. * @uses $pkg_elements sorts with {@link elementCmp} after sorting by
  2380. * package/subpackage alphabetically
  2381. * @access private
  2382. */
  2383. function sortIndexes()
  2384. {
  2385. phpDocumentor_out("\nSorting Indexes...");
  2386. flush();
  2387. uksort($this->elements,'strnatcasecmp');
  2388. if ($this->leftindex['classes'])
  2389. {
  2390. foreach($this->class_elements as $package => $o1)
  2391. {
  2392. foreach($o1 as $subpackage => $links)
  2393. {
  2394. usort($this->class_elements[$package][$subpackage],array($this,'compareLink'));
  2395. }
  2396. }
  2397. }
  2398. if ($this->leftindex['pages'])
  2399. {
  2400. foreach($this->page_elements as $package => $o1)
  2401. {
  2402. uksort($this->page_elements[$package],'strnatcasecmp');
  2403. foreach($o1 as $subpackage => $links)
  2404. {
  2405. usort($this->page_elements[$package][$subpackage],array($this,'compareLink'));
  2406. }
  2407. }
  2408. }
  2409. if ($this->leftindex['defines'])
  2410. {
  2411. foreach($this->define_elements as $package => $o1)
  2412. {
  2413. uksort($this->define_elements[$package],'strnatcasecmp');
  2414. foreach($o1 as $subpackage => $links)
  2415. {
  2416. usort($this->define_elements[$package][$subpackage],array($this,'compareLink'));
  2417. }
  2418. }
  2419. }
  2420. if ($this->leftindex['globals'])
  2421. {
  2422. foreach($this->global_elements as $package => $o1)
  2423. {
  2424. uksort($this->global_elements[$package],'strnatcasecmp');
  2425. foreach($o1 as $subpackage => $links)
  2426. {
  2427. usort($this->global_elements[$package][$subpackage],array($this,'compareLink'));
  2428. }
  2429. }
  2430. }
  2431. if ($this->leftindex['functions'])
  2432. {
  2433. foreach($this->function_elements as $package => $o1)
  2434. {
  2435. uksort($this->function_elements[$package],'strnatcasecmp');
  2436. foreach($o1 as $subpackage => $links)
  2437. {
  2438. usort($this->function_elements[$package][$subpackage],array($this,'compareLink'));
  2439. }
  2440. }
  2441. }
  2442. foreach($this->elements as $letter => $nothuing)
  2443. {
  2444. uasort($this->elements[$letter],array($this,"elementCmp"));
  2445. }
  2446. foreach($this->pkg_elements as $package => $els)
  2447. {
  2448. uksort($this->pkg_elements[$package],'strnatcasecmp');
  2449. foreach($this->pkg_elements[$package] as $subpackage => $els)
  2450. {
  2451. if (empty($els)) continue;
  2452. uksort($this->pkg_elements[$package][$subpackage],'strnatcasecmp');
  2453. foreach($els as $letter => $yuh)
  2454. {
  2455. usort($this->pkg_elements[$package][$subpackage][$letter],array($this,"elementCmp"));
  2456. }
  2457. }
  2458. }
  2459. phpDocumentor_out("done\n");
  2460. flush();
  2461. }
  2462. /**
  2463. * sorts {@link $page_contents} by element type as well as alphabetically
  2464. * @see $sort_page_contents_by_element_type
  2465. */
  2466. function sortPageContentsByElementType(&$pages)
  2467. {
  2468. foreach($this->page_contents as $package => $els)
  2469. {
  2470. foreach($this->page_contents[$package] as $subpackage => $els)
  2471. {
  2472. if (empty($els)) continue;
  2473. foreach($this->page_contents[$package][$subpackage] as $path => $stuff)
  2474. {
  2475. if (!count($pages[$path]->elements)) continue;
  2476. usort($pages[$path]->elements,array($this,'eltypecmp'));
  2477. usort($this->page_contents[$package][$subpackage][$path],array($this,'eltypecmp'));
  2478. if (isset($this->page_contents[$package][$subpackage][$path][0]))
  2479. $this->page_contents[$package][$subpackage][$path]['###main'] = $this->page_contents[$package][$subpackage][$path][0];
  2480. unset($this->page_contents[$package][$subpackage][$path][0]);
  2481. }
  2482. }
  2483. }
  2484. }
  2485. /**
  2486. * @access private
  2487. * @see Converter::sortIndexes()
  2488. */
  2489. function compareLink($a, $b)
  2490. {
  2491. return strnatcasecmp($a->name,$b->name);
  2492. }
  2493. /**
  2494. * @access private
  2495. * @see Converter::sortPageContentsByElementType()
  2496. */
  2497. function eltypecmp($a, $b)
  2498. {
  2499. if ($a->type == 'page') return -1;
  2500. if ($b->type == 'page') return 1;
  2501. return strnatcasecmp($a->type.$a->name,$b->type.$b->name);
  2502. }
  2503. /**
  2504. * does a nat case sort on the specified second level value of the array
  2505. *
  2506. * @param mixed $a
  2507. * @param mixed $b
  2508. * @return int
  2509. * @access private
  2510. */
  2511. function elementCmp ($a, $b)
  2512. {
  2513. return strnatcasecmp($a->getName(), $b->getName());
  2514. }
  2515. /**
  2516. * Used to stop conversion of @ignored or private @access classes
  2517. * @uses $killclass sets killclass based on the value of {@link Classes::$killclass}
  2518. * and {@link $package_output}
  2519. * @access private
  2520. */
  2521. function checkKillClass($class, $path)
  2522. {
  2523. $this->killclass = false;
  2524. if (isset($this->classes->killclass[$class]) && isset($this->classes->killclass[$class][$path])) $this->killclass = true;
  2525. if ($this->package_output)
  2526. {
  2527. $a = $this->classes->getClass($class, $path);
  2528. if (!in_array($a->docblock->package,$this->package_output)) $this->killclass = true;
  2529. }
  2530. if (PHPDOCUMENTOR_DEBUG && $this->killclass) debug("$class $path killed");
  2531. return $this->killclass;
  2532. }
  2533. /**
  2534. * @param abstractLink descendant of abstractLink
  2535. * @param array|parserTag list of @todos|@todo tag
  2536. * @access private
  2537. */
  2538. function addTodoLink($link, $todos)
  2539. {
  2540. $this->todoList[$link->package][] = array($link, $todos);
  2541. }
  2542. /**
  2543. * Adds all elements to the {@link $elements, $pkg_elements, $links},
  2544. * {@link $linkswithfile} and left indexes - Do not modify or override
  2545. * @access private
  2546. * @param parserBase any documentable element descendant of parserBase
  2547. * except parserTutorial
  2548. * @param false|parserPage only used to add a {@link parserPage} if the
  2549. * $element passed is a parserPage
  2550. * @staticvar string path of current page, used for {@link $page_contents} setup
  2551. */
  2552. function addElement(&$element,$pageel=false)
  2553. {
  2554. static $curpath = '';
  2555. if ($this->package_output)
  2556. {
  2557. if (!in_array($this->package, $this->package_output)) return;
  2558. }
  2559. if ($pageel && phpDocumentor_get_class($pageel) == 'parserdata')
  2560. {
  2561. if (isset($pageel->docblock) && phpDocumentor_get_class($pageel->docblock) == 'parserdocblock')
  2562. {
  2563. $a = $pageel->docblock->getKeyword('todo');
  2564. if ($a)
  2565. {
  2566. $this->addTodoLink($this->addLink($element),$a);
  2567. }
  2568. }
  2569. }
  2570. if (isset($element->docblock))
  2571. {
  2572. $a = $element->docblock->getKeyword('access');
  2573. if (is_object($a)) $a = $a->getString();
  2574. if (!$this->parseprivate && ($a == 'private'))
  2575. return;
  2576. $a = $element->docblock->getKeyword('todo');
  2577. if ($a)
  2578. {
  2579. if ($element->type != 'include') {
  2580. $this->addTodoLink($this->addLink($element),$a);
  2581. } else {
  2582. addWarning(PDERROR_NOTODO_INCLUDE, $element->getLineNumber(),
  2583. $element->getPath());
  2584. }
  2585. }
  2586. }
  2587. $startPositionOfElementName = 0; // which character of the element name actually starts its textual name
  2588. switch($element->type)
  2589. {
  2590. case 'page' :
  2591. if ($this->sort_absolutely_everything)
  2592. {
  2593. $this->package_elements[$element->package][$element->subpackage]['page'][$element->getPath()][] = $pageel;
  2594. }
  2595. $link = $this->addLink($element);
  2596. $curpath = $element->getPath();
  2597. if ($this->leftindex['pages'])
  2598. $this->page_elements[$element->package][$element->subpackage][] = $link;
  2599. $this->page_contents[$element->package][$element->subpackage][$curpath]['###main'] = $link;
  2600. break;
  2601. case 'class' :
  2602. if ($this->sort_absolutely_everything)
  2603. {
  2604. $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][] = $element;
  2605. }
  2606. $link = $this->addLink($element);
  2607. if ($this->leftindex['classes'])
  2608. $this->class_elements[$element->docblock->package][$element->docblock->subpackage][] = $link;
  2609. $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class]['###main'] = $link;
  2610. break;
  2611. case 'include' :
  2612. if ($this->sort_absolutely_everything)
  2613. {
  2614. $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][] = $element;
  2615. }
  2616. $link = $this->addLink($element);
  2617. break;
  2618. case 'define' :
  2619. if ($this->sort_absolutely_everything)
  2620. {
  2621. $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][] = $element;
  2622. }
  2623. $link = $this->addLink($element);
  2624. if ($this->leftindex['defines'])
  2625. $this->define_elements[$element->docblock->package][$element->docblock->subpackage][] = $link;
  2626. $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][] = $link;
  2627. break;
  2628. case 'global' :
  2629. if ($this->sort_absolutely_everything)
  2630. {
  2631. $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][] = $element;
  2632. }
  2633. $link = $this->addLink($element);
  2634. $startPositionOfElementName = 1; // lose the leading "$" character
  2635. if ($this->leftindex['globals'])
  2636. $this->global_elements[$element->docblock->package][$element->docblock->subpackage][] = $link;
  2637. $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][] = $link;
  2638. break;
  2639. case 'var' :
  2640. if ($this->sort_absolutely_everything)
  2641. {
  2642. $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][] = $element;
  2643. }
  2644. $link = $this->addLink($element);
  2645. $startPositionOfElementName = 1; // lose the leading "$" character
  2646. $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][] = $link;
  2647. break;
  2648. case 'const' :
  2649. if ($this->sort_absolutely_everything)
  2650. {
  2651. $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][] = $element;
  2652. }
  2653. $link = $this->addLink($element);
  2654. $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][] = $link;
  2655. break;
  2656. case 'method' :
  2657. if ($this->sort_absolutely_everything)
  2658. {
  2659. $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['class'][$this->class][] = $element;
  2660. }
  2661. $link = $this->addLink($element);
  2662. $this->class_contents[$element->docblock->package][$element->docblock->subpackage][$this->class][] = $link;
  2663. break;
  2664. case 'function' :
  2665. if ($this->sort_absolutely_everything)
  2666. {
  2667. $this->package_elements[$element->docblock->package][$element->docblock->subpackage]['page'][$curpath][] = $element;
  2668. }
  2669. $link = $this->addLink($element);
  2670. if ($this->leftindex['functions'])
  2671. $this->function_elements[$element->docblock->package][$element->docblock->subpackage][] = $link;
  2672. $this->page_contents[$element->docblock->package][$element->docblock->subpackage][$curpath][] = $link;
  2673. break;
  2674. default :
  2675. break;
  2676. }
  2677. if ($element->getType() != 'include')
  2678. {
  2679. if ($element->getType() == 'var' || $element->getType() == 'method'|| $element->getType() == 'const')
  2680. {
  2681. $this->links[$this->package][$this->subpackage][$element->getType()][$element->class][$element->getName()] = $link;
  2682. $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->class][$element->getName()] = $link;
  2683. } else
  2684. {
  2685. if ($element->type == 'page')
  2686. {
  2687. $this->links[$this->package][$this->subpackage][$element->getType()][$element->getFile()] = $link;
  2688. $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->getFile()] = $link;
  2689. } else
  2690. {
  2691. $this->links[$this->package][$this->subpackage][$element->getType()][$element->getName()] = $link;
  2692. $this->linkswithfile[$this->package][$this->subpackage][$element->getType()][$element->getPath()][$element->getName()] = $link;
  2693. }
  2694. }
  2695. }
  2696. if ($element->type == 'page')
  2697. {
  2698. $this->elements[substr(strtolower($element->getFile()),$startPositionOfElementName,1)][] = $element;
  2699. $this->pkg_elements[$this->package][$this->subpackage][substr(strtolower($element->getFile()),$startPositionOfElementName,1)][] = $element;
  2700. } else
  2701. {
  2702. $this->elements[substr(strtolower($element->getName()),$startPositionOfElementName,1)][] = $element;
  2703. $this->pkg_elements[$this->package][$this->subpackage][substr(strtolower($element->getName()),$startPositionOfElementName,1)][] = $element;
  2704. }
  2705. }
  2706. /**
  2707. * returns an abstract link to element. Do not modify or override
  2708. *
  2709. * This method should only be called in process of Conversion, unless
  2710. * $element is a parserPage, or $page is set to true, and $element is
  2711. * not a parserPage
  2712. * @return abstractLink abstractLink descendant
  2713. * @access private
  2714. * @param parserElement element to add a new link (descended from
  2715. * {@link abstractLink})to the {@link $links} array
  2716. * @param string classname for elements that are class-based (this may be
  2717. * deprecated in the future, as the classname
  2718. * should be contained within the element. if $element is a
  2719. * page, this parameter is a package name
  2720. * @param string subpackage name for page elements
  2721. */
  2722. function addLink(&$element,$page = false)
  2723. {
  2724. if ($page)
  2725. {
  2726. // create a fake parserPage to extract the fileAlias for this link
  2727. $fakepage = new parserPage;
  2728. $fakepage->setPath($element->getPath());
  2729. $fakepage->setFile(basename($element->getPath()));
  2730. $this->curname = $this->getPageName($fakepage);
  2731. }
  2732. switch($element->type)
  2733. {
  2734. case 'function':
  2735. $x = new functionLink;
  2736. $x->addLink($element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
  2737. return $x;
  2738. break;
  2739. case 'define':
  2740. $x = new defineLink;
  2741. $x->addLink($element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
  2742. return $x;
  2743. break;
  2744. case 'global':
  2745. $x = new globalLink;
  2746. $x->addLink($element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
  2747. return $x;
  2748. break;
  2749. case 'class':
  2750. $x = new classLink;
  2751. $x->addLink($element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
  2752. return $x;
  2753. break;
  2754. case 'method':
  2755. $x = new methodLink;
  2756. $x->addLink($this->class, $element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
  2757. return $x;
  2758. break;
  2759. case 'var':
  2760. $x = new varLink;
  2761. $x->addLink($this->class, $element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
  2762. return $x;
  2763. break;
  2764. case 'const':
  2765. $x = new constLink;
  2766. $x->addLink($this->class, $element->getPath(), $this->curname, $element->name, $element->docblock->package, $element->docblock->subpackage, $element->docblock->category);
  2767. return $x;
  2768. break;
  2769. case 'page':
  2770. $x = new pageLink;
  2771. $x->addLink($element->getPath(),$this->getPageName($element),$element->file,$element->package, $element->subpackage, $element->category);
  2772. return $x;
  2773. break;
  2774. }
  2775. }
  2776. /**
  2777. * Return a tree of all classes that extend this class
  2778. *
  2779. * The data structure returned is designed for a non-recursive algorithm,
  2780. * and is somewhat complex.
  2781. * In most cases, the array returned is:
  2782. *
  2783. * <pre>
  2784. * array('#root' =>
  2785. * array('link' => {@link classLink} to $class,
  2786. * 'parent' => false,
  2787. * 'children' => array(array('class' => 'childclass1',
  2788. * 'package' => 'child1package'),
  2789. * array('class' => 'childclass2',
  2790. * 'package' => 'child2package'),...
  2791. * )
  2792. * ),
  2793. * 'child1package#childclass1' =>
  2794. * array('link' => {@link classLink} to childclass1,
  2795. * 'parent' => '#root',
  2796. * 'children' => array(array('class' => 'kidclass',
  2797. * 'package' => 'kidpackage'),...
  2798. * )
  2799. * ),
  2800. * 'kidpackage#kidclass' =>
  2801. * array('link' => {@link classLink} to kidclass,
  2802. * 'parent' => 'child1package#childclass1',
  2803. * 'children' => array() // no children
  2804. * ),
  2805. * ....
  2806. * )
  2807. *</pre>
  2808. *
  2809. * To describe this format using language, every class in the tree has an
  2810. * entry in the first level of the array. The index for all child
  2811. * classes that extend the root class is childpackage#childclassname.
  2812. * Each entry in the array has 3 elements: link, parent, and children.
  2813. * <ul>
  2814. * <li>link - a {@link classLink} to the current class</li>
  2815. * <li>parent - a {@link classLink} to the class's parent, or false (except for one special case described below)</li>
  2816. * <li>children - an array of arrays, each entry has a 'class' and 'package' index to the child class,
  2817. * used to find the entry in the big array</li>
  2818. * </ul>
  2819. *
  2820. * special cases are when the #root class has a parent in another package,
  2821. * or when the #root class extends a class not found
  2822. * by phpDocumentor. In the first case, parent will be a
  2823. * classLink to the parent class. In the second, parent will be the
  2824. * extends clause, as in:
  2825. * <code>
  2826. * class X extends Y
  2827. * {
  2828. * ...
  2829. * }
  2830. * </code>
  2831. * in this case, the #root entry will be array('link' => classLink to X, 'parent' => 'Y', children => array(...))
  2832. *
  2833. * The fastest way to design a method to process the array returned
  2834. * is to copy HTMLframesConverter::getRootTree() into
  2835. * your converter and to modify the html to whatever output format you are going to use
  2836. * @see HTMLframesConverter::getRootTree()
  2837. * @param string class name
  2838. * @param string
  2839. * @param string
  2840. * @return array Format: see docs
  2841. */
  2842. function getSortedClassTreeFromClass($class,$package,$subpackage)
  2843. {
  2844. $my_tree = array();
  2845. $root = $this->classes->getClassByPackage($class,$package);
  2846. if (!$root) return false;
  2847. $class_children = $this->classes->getDefiniteChildren($class,$root->curfile);
  2848. if (!$class_children)
  2849. {
  2850. // special case: parent class is found, but is not part of this package, class has no children
  2851. if (is_array($root->parent))
  2852. {
  2853. $x = $root->getParent($this);
  2854. if ($x->docblock->package != $package)
  2855. {
  2856. $v = Converter::getClassLink($root->getName(),$package,$root->getPath());
  2857. return array('#root' => array('link' => $v,'parent' => Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath()), 'children' => array()));
  2858. }
  2859. } else
  2860. { // class has normal situation, no children
  2861. if (is_string($root->getParent($this)))
  2862. return array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath()), 'parent' => $root->getExtends(),'children' => array()));
  2863. else
  2864. return array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath()), 'parent' => false, 'children' => array()));
  2865. }
  2866. }
  2867. // special case: parent class is found, but is not part of this package, class has children
  2868. if (is_array($root->parent))
  2869. {
  2870. $x = $root->getParent($this);
  2871. if ($x->docblock->package != $package)
  2872. {
  2873. $v = Converter::getClassLink($root->getName(),$package,$root->getPath());
  2874. $my_tree = array('#root' => array('link' => $v, 'parent' => Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath()), 'children' => array()));
  2875. } else
  2876. {
  2877. }
  2878. } else
  2879. $my_tree = array('#root' => array('link' => Converter::getClassLink($root->getName(),$package,$root->getPath()), 'parent' => false, 'children' => array()));
  2880. // location of tree walker
  2881. $cur = '#root';
  2882. $lastcur = array(array(false,0));
  2883. $childpos = 0;
  2884. if (isset($class_children))
  2885. {
  2886. do
  2887. {
  2888. if (!$class_children)
  2889. {
  2890. list($cur, $childpos) = array_pop($lastcur);
  2891. if (isset($my_tree[$cur]['children'][$childpos + 1]))
  2892. {
  2893. array_push($lastcur, array($cur, $childpos + 1));
  2894. $par = $cur;
  2895. $cur = $my_tree[$cur]['children'][$childpos + 1];
  2896. $x = $this->classes->getClassByPackage($cur['class'],$cur['package']);
  2897. $childpos = 0;
  2898. $cur = $cur['package'] . '#' . $cur['class'];
  2899. $my_tree[$cur]['link'] = Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath());
  2900. $my_tree[$cur]['parent'] = $par;
  2901. $my_tree[$cur]['children'] = array();
  2902. $class_children = $this->classes->getDefiniteChildren($x->getName(), $x->curfile);
  2903. continue;
  2904. } else
  2905. {
  2906. $class_children = false;
  2907. continue;
  2908. }
  2909. }
  2910. foreach($class_children as $chileclass => $chilefile)
  2911. {
  2912. $ch = $this->classes->getClass($chileclass,$chilefile);
  2913. $my_tree[$cur]['children'][] = array('class' => $ch->getName(), 'package' => $ch->docblock->package);
  2914. }
  2915. usort($my_tree[$cur]['children'],'rootcmp');
  2916. if (isset($my_tree[$cur]['children'][$childpos]))
  2917. {
  2918. array_push($lastcur, array($cur, $childpos));
  2919. $par = $cur;
  2920. $cur = $my_tree[$cur]['children'][$childpos];
  2921. $x = $this->classes->getClassByPackage($cur['class'],$cur['package']);
  2922. $cur = $cur['package'] . '#' . $cur['class'];
  2923. $my_tree[$cur]['link'] = Converter::getClassLink($x->getName(),$x->docblock->package,$x->getPath());
  2924. $my_tree[$cur]['parent'] = $par;
  2925. $my_tree[$cur]['children'] = array();
  2926. $childpos = 0;
  2927. $class_children = $this->classes->getDefiniteChildren($x->getName(), $x->curfile);
  2928. } else
  2929. {
  2930. list($cur, $childpos) = array_pop($lastcur);
  2931. }
  2932. } while ($cur);
  2933. }
  2934. return $my_tree;
  2935. }
  2936. /**
  2937. * do not override
  2938. * @return bool true if a link to this class exists in package $package and subpackage $subpackage
  2939. * @param string $expr class name
  2940. * @param string $package package to search in
  2941. * @param string $subpackage subpackage to search in
  2942. * @access private
  2943. */
  2944. function isLinkedClass($expr,$package,$subpackage,$file=false)
  2945. {
  2946. if ($file)
  2947. return isset($this->linkswithfile[$package][$subpackage]['class'][$file][$expr]);
  2948. return isset($this->links[$package][$subpackage]['class'][$expr]);
  2949. }
  2950. /**
  2951. * do not override
  2952. * @return bool true if a link to this function exists in package $package and subpackage $subpackage
  2953. * @param string $expr function name
  2954. * @param string $package package to search in
  2955. * @param string $subpackage subpackage to search in
  2956. * @access private
  2957. */
  2958. function isLinkedFunction($expr,$package,$subpackage,$file=false)
  2959. {
  2960. if ($file)
  2961. return isset($this->linkswithfile[$package][$subpackage]['function'][$file][$expr]);
  2962. return isset($this->links[$package][$subpackage]['function'][$expr]);
  2963. }
  2964. /**
  2965. * do not override
  2966. * @return bool true if a link to this define exists in package $package and subpackage $subpackage
  2967. * @param string $expr define name
  2968. * @param string $package package to search in
  2969. * @param string $subpackage subpackage to search in
  2970. * @access private
  2971. */
  2972. function isLinkedDefine($expr,$package,$subpackage,$file=false)
  2973. {
  2974. if ($file)
  2975. return isset($this->linkswithfile[$package][$subpackage]['define'][$file][$expr]);
  2976. return isset($this->links[$package][$subpackage]['define'][$expr]);
  2977. }
  2978. /**
  2979. * do not override
  2980. * @return bool true if a link to this define exists in package $package and subpackage $subpackage
  2981. * @param string $expr define name
  2982. * @param string $package package to search in
  2983. * @param string $subpackage subpackage to search in
  2984. * @access private
  2985. */
  2986. function isLinkedGlobal($expr,$package,$subpackage,$file=false)
  2987. {
  2988. if ($file)
  2989. return isset($this->linkswithfile[$package][$subpackage]['global'][$file][$expr]);
  2990. return isset($this->links[$package][$subpackage]['global'][$expr]);
  2991. }
  2992. /**
  2993. * do not override
  2994. * @return bool true if a link to this procedural page exists in package $package and subpackage $subpackage
  2995. * @param string $expr procedural page name
  2996. * @param string $package package to search in
  2997. * @param string $subpackage subpackage to search in
  2998. * @access private
  2999. */
  3000. function isLinkedPage($expr,$package,$subpackage,$path=false)
  3001. {
  3002. if ($path)
  3003. return isset($this->linkswithfile[$package][$subpackage]['page'][$path][$expr]);
  3004. return isset($this->links[$package][$subpackage]['page'][$expr]);
  3005. }
  3006. /**
  3007. * do not override
  3008. * @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class
  3009. * @param string $expr method name
  3010. * @param string $class class name
  3011. * @param string $package package to search in
  3012. * @param string $subpackage subpackage to search in
  3013. * @access private
  3014. */
  3015. function isLinkedMethod($expr,$package,$subpackage,$class,$file=false)
  3016. {
  3017. if ($file)
  3018. return isset($this->linkswithfile[$package][$subpackage]['method'][$file][$class][$expr]);
  3019. return isset($this->links[$package][$subpackage]['method'][$class][$expr]);
  3020. }
  3021. /**
  3022. * do not override
  3023. * @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class
  3024. * @param string $expr var name
  3025. * @param string $class class name
  3026. * @param string $package package to search in
  3027. * @param string $subpackage subpackage to search in
  3028. * @access private
  3029. */
  3030. function isLinkedVar($expr,$package,$subpackage,$class,$file=false)
  3031. {
  3032. if ($file)
  3033. return isset($this->linkswithfile[$package][$subpackage]['var'][$file][$class][$expr]);
  3034. return isset($this->links[$package][$subpackage]['var'][$class][$expr]);
  3035. }
  3036. /**
  3037. * do not override
  3038. * @return bool true if a link to this method exists in package $package, subpackage $subpackage and class $class
  3039. * @param string $expr constant name
  3040. * @param string $class class name
  3041. * @param string $package package to search in
  3042. * @param string $subpackage subpackage to search in
  3043. * @access private
  3044. */
  3045. function isLinkedConst($expr,$package,$subpackage,$class,$file=false)
  3046. {
  3047. if ($file)
  3048. return isset($this->linkswithfile[$package][$subpackage]['const'][$file][$class][$expr]);
  3049. return isset($this->links[$package][$subpackage]['const'][$class][$expr]);
  3050. }
  3051. /**
  3052. * return false or a {@link classLink} to $expr
  3053. * @param string $expr class name
  3054. * @param string $package package name
  3055. * @return mixed returns a {@link classLink} or false if the element is not found in package $package
  3056. * @see classLink
  3057. */
  3058. function getClassLink($expr,$package,$file=false, $text = false)
  3059. {
  3060. if (!isset($this->links[$package])) return false;
  3061. foreach($this->links[$package] as $subpackage => $notused)
  3062. {
  3063. if ($this->isLinkedClass($expr,$package,$subpackage,$file))
  3064. {
  3065. if ($file)
  3066. {
  3067. return $this->linkswithfile[$package][$subpackage]['class'][$file][$expr];
  3068. }
  3069. return $this->links[$package][$subpackage]['class'][$expr];
  3070. }
  3071. }
  3072. return false;
  3073. }
  3074. /**
  3075. * return false or a {@link functionLink} to $expr
  3076. * @param string $expr function name
  3077. * @param string $package package name
  3078. * @return mixed returns a {@link functionLink} or false if the element is not found in package $package
  3079. * @see functionLink
  3080. */
  3081. function getFunctionLink($expr,$package,$file=false, $text = false)
  3082. {
  3083. if (!isset($this->links[$package])) return false;
  3084. foreach($this->links[$package] as $subpackage => $notused)
  3085. {
  3086. if ($this->isLinkedFunction($expr,$package,$subpackage,$file))
  3087. {
  3088. if ($file)
  3089. {
  3090. return $this->linkswithfile[$package][$subpackage]['function'][$file][$expr];
  3091. }
  3092. return $this->links[$package][$subpackage]['function'][$expr];
  3093. }
  3094. }
  3095. return false;
  3096. }
  3097. /**
  3098. * return false or a {@link defineLink} to $expr
  3099. * @param string $expr constant name
  3100. * @param string $package package name
  3101. * @return mixed returns a {@link defineLink} or false if the element is not found in package $package
  3102. * @see defineLink
  3103. */
  3104. function getDefineLink($expr,$package,$file=false, $text = false)
  3105. {
  3106. if (!isset($this->links[$package])) return false;
  3107. foreach($this->links[$package] as $subpackage => $notused)
  3108. {
  3109. if ($this->isLinkedDefine($expr,$package,$subpackage,$file))
  3110. {
  3111. if ($file)
  3112. {
  3113. return $this->linkswithfile[$package][$subpackage]['define'][$file][$expr];
  3114. }
  3115. return $this->links[$package][$subpackage]['define'][$expr];
  3116. }
  3117. }
  3118. return false;
  3119. }
  3120. /**
  3121. * return false or a {@link globalLink} to $expr
  3122. * @param string $expr global variable name (with leading $)
  3123. * @param string $package package name
  3124. * @return mixed returns a {@link defineLink} or false if the element is not found in package $package
  3125. * @see defineLink
  3126. */
  3127. function getGlobalLink($expr,$package,$file=false, $text = false)
  3128. {
  3129. if (!isset($this->links[$package])) return false;
  3130. foreach($this->links[$package] as $subpackage => $notused)
  3131. {
  3132. if ($this->isLinkedGlobal($expr,$package,$subpackage,$file))
  3133. {
  3134. if ($file)
  3135. {
  3136. return $this->linkswithfile[$package][$subpackage]['global'][$file][$expr];
  3137. }
  3138. return $this->links[$package][$subpackage]['global'][$expr];
  3139. }
  3140. }
  3141. return false;
  3142. }
  3143. /**
  3144. * return false or a {@link pageLink} to $expr
  3145. * @param string $expr procedural page name
  3146. * @param string $package package name
  3147. * @return mixed returns a {@link pageLink} or false if the element is not found in package $package
  3148. * @see pageLink
  3149. */
  3150. function getPageLink($expr,$package,$path = false, $text = false, $packages = false)
  3151. {
  3152. if (!isset($this->links[$package])) return false;
  3153. foreach($this->links[$package] as $subpackage => $notused)
  3154. {
  3155. if ($this->isLinkedPage($expr,$package,$subpackage,$path))
  3156. {
  3157. if ($path)
  3158. {
  3159. return $this->linkswithfile[$package][$subpackage]['page'][$path][$expr];
  3160. }
  3161. return $this->links[$package][$subpackage]['page'][$expr];
  3162. }
  3163. }
  3164. return false;
  3165. }
  3166. /**
  3167. * return false or a {@link methodLink} to $expr in $class
  3168. * @param string $expr method name
  3169. * @param string $class class name
  3170. * @param string $package package name
  3171. * @return mixed returns a {@link methodLink} or false if the element is not found in package $package, class $class
  3172. * @see methodLink
  3173. */
  3174. function getMethodLink($expr,$class,$package,$file=false, $text = false)
  3175. {
  3176. $expr = trim($expr);
  3177. $class = trim($class);
  3178. if (!isset($this->links[$package])) return false;
  3179. foreach($this->links[$package] as $subpackage => $notused)
  3180. {
  3181. if ($this->isLinkedMethod($expr,$package,$subpackage,$class,$file))
  3182. {
  3183. if ($file)
  3184. {
  3185. return $this->linkswithfile[$package][$subpackage]['method'][$file][$class][$expr];
  3186. }
  3187. return $this->links[$package][$subpackage]['method'][$class][$expr];
  3188. }
  3189. }
  3190. return false;
  3191. }
  3192. /**
  3193. * return false or a {@link varLink} to $expr in $class
  3194. * @param string $expr var name
  3195. * @param string $class class name
  3196. * @param string $package package name
  3197. * @return mixed returns a {@link varLink} or false if the element is not found in package $package, class $class
  3198. * @see varLink
  3199. */
  3200. function getVarLink($expr,$class,$package,$file=false, $text = false)
  3201. {
  3202. $expr = trim($expr);
  3203. $class = trim($class);
  3204. if (!isset($this->links[$package])) return false;
  3205. foreach($this->links[$package] as $subpackage => $notused)
  3206. {
  3207. if ($this->isLinkedVar($expr,$package,$subpackage,$class,$file))
  3208. {
  3209. if ($file)
  3210. {
  3211. return $this->linkswithfile[$package][$subpackage]['var'][$file][$class][$expr];
  3212. }
  3213. return $this->links[$package][$subpackage]['var'][$class][$expr];
  3214. }
  3215. }
  3216. return false;
  3217. }
  3218. /**
  3219. * return false or a {@link constLink} to $expr in $class
  3220. * @param string $expr constant name
  3221. * @param string $class class name
  3222. * @param string $package package name
  3223. * @return mixed returns a {@link varLink} or false if the element is not found in package $package, class $class
  3224. * @see constLink
  3225. */
  3226. function getConstLink($expr,$class,$package,$file=false, $text = false)
  3227. {
  3228. $expr = trim($expr);
  3229. $class = trim($class);
  3230. if (!isset($this->links[$package])) return false;
  3231. foreach($this->links[$package] as $subpackage => $notused)
  3232. {
  3233. if ($this->isLinkedConst($expr,$package,$subpackage,$class,$file))
  3234. {
  3235. if ($file)
  3236. {
  3237. return $this->linkswithfile[$package][$subpackage]['const'][$file][$class][$expr];
  3238. }
  3239. return $this->links[$package][$subpackage]['const'][$class][$expr];
  3240. }
  3241. }
  3242. return false;
  3243. }
  3244. /**
  3245. * The meat of the @tutorial tag and inline {@}tutorial} tag
  3246. *
  3247. * Take a string and return an abstract link to the tutorial it represents.
  3248. * Since tutorial naming literally works like the underlying filesystem, the
  3249. * way to reference the tutorial is similar. Tutorials are located in a
  3250. * subdirectory of any directory parsed, which is named 'tutorials/' (we
  3251. * try to make things simple when we can :). They are further organized by
  3252. * package and subpackage as:
  3253. *
  3254. * tutorials/package/subpackage
  3255. *
  3256. * and the files are named *.cls, *.pkg, or *.proc, and so a link to a tutorial
  3257. * named file.cls can be referenced (depending on context) as any of:
  3258. *
  3259. * <code>
  3260. * * @tutorial package/subpackage/file.cls
  3261. * * @tutorial package/file.cls
  3262. * * @tutorial file.cls
  3263. * </code>
  3264. *
  3265. * The first case will only be needed if file.cls exists in both the current
  3266. * package, in anotherpackage/file.cls and in anotherpackage/subpackage/file.cls
  3267. * and you wish to reference the one in anotherpackage/subpackage.
  3268. * The second case is only needed if you wish to reference file.cls in another
  3269. * package and it is unique in that package. the third will link to the first
  3270. * file.cls it finds using this search method:
  3271. *
  3272. * <ol>
  3273. * <li>current package/subpackage</li>
  3274. * <li>all other subpackages of current package</li>
  3275. * <li>parent package, if this package has classes that extend classes in
  3276. * another package</li>
  3277. * <li>all other packages</li>
  3278. * </ol>
  3279. * @return tutorialLink|string returns either a link, or the original text, if not found
  3280. * @param string the original expression
  3281. * @param string package to look in first
  3282. * @param string subpackage to look in first
  3283. * @param array array of package names to search in if not found in parent packages.
  3284. * This is used to limit the search, phpDocumentor automatically searches
  3285. * all packages
  3286. * @since 1.2
  3287. */
  3288. function getTutorialLink($expr, $package = false, $subpackage = false, $packages = false)
  3289. {
  3290. // is $expr a comma-delimited list?
  3291. if (strpos($expr,','))
  3292. {
  3293. $a = explode(',',$expr);
  3294. $b = array();
  3295. for($i=0;$i<count($a);$i++)
  3296. {
  3297. // if so return each component with a link
  3298. $b[] = Converter::getTutorialLink(trim($a[$i]));
  3299. }
  3300. return $b;
  3301. }
  3302. $subsection = '';
  3303. if (strpos($expr,'#'))
  3304. {
  3305. $a = explode('#',$expr);
  3306. $org = $expr;
  3307. $expr = $a[0];
  3308. $subsection = $a[1];
  3309. }
  3310. if (strpos($expr,'/'))
  3311. {
  3312. $a = explode('/',$expr);
  3313. if (count($a) == 3)
  3314. {
  3315. return Converter::getTutorialLink($a[2],$a[0],$a[1],array());
  3316. }
  3317. if (count($a) == 2)
  3318. {
  3319. return Converter::getTutorialLink($a[1],$a[0],false,array());
  3320. }
  3321. }
  3322. if (!$package) $package = $this->package;
  3323. if (!$subpackage) $subpackage = $this->subpackage;
  3324. if (!isset($this->all_packages[$package])) return $expr;
  3325. elseif (isset($packages[$package])) unset($packages[$package]);
  3326. $ext = pathinfo($expr, PATHINFO_EXTENSION);
  3327. if (isset($this->tutorials[$package][$subpackage][$ext][$expr]))
  3328. {
  3329. $a = $this->tutorials[$package][$subpackage][$ext][$expr];
  3330. $link = new tutorialLink;
  3331. $link->addLink($subsection,$a->path,$a->name,$a->package,$a->subpackage,$a->getTitle($this,$subsection));
  3332. return $link;
  3333. }
  3334. do
  3335. {
  3336. if (!is_array($packages))
  3337. {
  3338. $packages = $this->all_packages;
  3339. if (isset($packages[$package])) unset($packages[$package]);
  3340. }
  3341. if (isset($this->tutorials[$package]))
  3342. {
  3343. if (isset($this->tutorials[$package][$subpackage][$ext][$expr]))
  3344. {
  3345. $a = $this->tutorials[$package][$subpackage][$ext][$expr];
  3346. $link = new tutorialLink;
  3347. $link->addLink($subsection,$a->path,$a->name,$a->package,$a->subpackage,$a->getTitle($this));
  3348. return $link;
  3349. } else
  3350. {
  3351. foreach($this->tutorials[$package] as $subpackage => $stuff)
  3352. {
  3353. if (isset($stuff[$ext][$expr]))
  3354. {
  3355. $a = $stuff[$ext][$expr];
  3356. $link = new tutorialLink;
  3357. $link->addLink($subsection,$a->path,$a->name,$a->package,$a->subpackage,$a->getTitle($this));
  3358. return $link;
  3359. }
  3360. }
  3361. }
  3362. }
  3363. // try other packages
  3364. // look in parent package first, if found
  3365. if (isset($this->package_parents[$package]))
  3366. {
  3367. $p1 = $package;
  3368. $package = $this->package_parents[$package];
  3369. } else
  3370. {
  3371. // no parent package, so start with the first one that's left
  3372. list($package,) = @each($packages);
  3373. }
  3374. if ($package)
  3375. {
  3376. if (isset($packages[$package])) unset($packages[$package]);
  3377. }
  3378. } while (count($packages) || $package);
  3379. addWarning(PDERROR_TUTORIAL_NOT_FOUND,$expr);
  3380. return $expr;
  3381. }
  3382. /**
  3383. * The meat of the @see tag and inline {@}link} tag
  3384. *
  3385. * $expr is a string with many allowable formats:
  3386. * <ol>
  3387. * <li>proceduralpagename.ext</li>
  3388. * <li>constant_name</li>
  3389. * <li>classname::function()</li>
  3390. * <li>classname::constantname</li> (new 1.2.4)
  3391. * <li>classname::$variablename</li>
  3392. * <li>classname</li>
  3393. * <li>object classname</li>
  3394. * <li>function functionname()</li>
  3395. * <li>global $globalvarname</li>
  3396. * <li>packagename#expr where expr is any of the above</li>
  3397. * </ol>
  3398. *
  3399. * New in version 1.1, you can explicitly specify a package to link to that
  3400. * is different from the current package. Use the # operator
  3401. * to specify a new package, as in tests#bug-540368.php (which should appear
  3402. * as a link like: "{@link tests#bug-540368.php}"). This
  3403. * example links to the procedural page bug-540368.php in package
  3404. * tests. Also, the "function" operator is now used to specifically
  3405. * link to a function instead of a method in the current class.
  3406. *
  3407. * <code>
  3408. * class myclass
  3409. * {
  3410. * // from inside the class definition, use "function conflict()" to refer to procedural function "conflict()"
  3411. * function conflict()
  3412. * {
  3413. * }
  3414. * }
  3415. *
  3416. * function conflict()
  3417. * {
  3418. * }
  3419. * </code>
  3420. *
  3421. * If classname:: is not present, and the see tag is in a documentation
  3422. * block within a class, then the function uses the classname to
  3423. * search for $expr as a function or variable within classname, or any of its parent classes.
  3424. * given an $expr without '$', '::' or '()' getLink first searches for
  3425. * classes, procedural pages, constants, global variables, and then searches for
  3426. * methods and variables within the default class, and finally for any function
  3427. *
  3428. * @param string $expr expression to search for a link
  3429. * @param string $package package to start searching in
  3430. * @param array $packages list of all packages to search in
  3431. * @return mixed getLink returns a descendant of {@link abstractLink} if it finds a link, otherwise it returns a string
  3432. * @see getPageLink(), getDefineLink(), getVarLink(), getFunctionLink(), getClassLink()
  3433. * @see pageLink, functionLink, defineLink, classLink, methodLink, varLink
  3434. */
  3435. function &getLink($expr, $package = false, $packages = false)
  3436. {
  3437. // is $expr a comma-delimited list?
  3438. if (strpos($expr,','))
  3439. {
  3440. $a = explode(',',$expr);
  3441. $b = array();
  3442. for($i=0;$i<count($a);$i++)
  3443. {
  3444. // if so return each component with a link
  3445. $b[] = Converter::getLink(trim($a[$i]));
  3446. }
  3447. return $b;
  3448. }
  3449. if (strpos($expr,'#'))
  3450. {
  3451. $a = explode('#',$expr);
  3452. if (count($a) == 2)
  3453. { // can have exactly 1 package override, otherwise it's ignored
  3454. // feature 564991, link to php manual
  3455. if ($a[0] == 'PHP_MANUAL') {
  3456. $s = 'http://www.php.net/'.$a[1];
  3457. return $s;
  3458. }
  3459. $s = &Converter::getLink($a[1],$a[0],array());
  3460. return $s;
  3461. }
  3462. }
  3463. $a = &$this->_getLink($expr, $package, $packages);
  3464. return $a;
  3465. }
  3466. /**
  3467. * @access private
  3468. */
  3469. function &_getLink($expr, $package = false, $packages = false)
  3470. {
  3471. if (!$package) $package = $this->package;
  3472. //
  3473. if (!isset($this->all_packages[$package])) return $expr;
  3474. elseif (isset($packages[$package])) unset($packages[$package]);
  3475. $links = &$this->links;
  3476. $class = $this->class;
  3477. if (strpos($expr,'function ') === 0)
  3478. { // asking for a function, not a method
  3479. if ($test = Converter::getFunctionLink(str_replace('function ','',str_replace('()','',$expr)), $package)) return $test;
  3480. else return $expr;
  3481. }
  3482. if (strpos($expr,'global ') === 0)
  3483. { // asking for a global variable
  3484. if ($test = Converter::getGlobalLink(str_replace('global ','',$expr), $package)) return $test;
  3485. else return $expr;
  3486. }
  3487. if (strpos($expr,'object ') === 0)
  3488. { // asking for a class
  3489. if ($test = Converter::getClassLink(str_replace('object ','',$expr), $package)) return $test;
  3490. else return $expr;
  3491. }
  3492. if (strpos($expr,'constant ') === 0)
  3493. { // asking for a class
  3494. if ($test = Converter::getDefineLink(str_replace('constant ','',$expr), $package)) return $test;
  3495. else return $expr;
  3496. }
  3497. // are we in a class?
  3498. if ($class)
  3499. {
  3500. // is $expr simply a word? see if it is the class
  3501. if (trim($expr) == $class)
  3502. {
  3503. if ($test = Converter::getClassLink(trim(str_replace('object ','',$expr)),$package)) return $test;
  3504. }
  3505. // if not, check to see if it is a method or variable of this class tree
  3506. if (!strpos($expr,'::'))
  3507. {
  3508. // if get is neither get() nor $get, assume get is a function, add () to make get()
  3509. if (strpos($expr,'$') !== 0 && !strpos($expr,'()')) //$get = $get.'()';
  3510. {
  3511. if ($a = $this->getLinkMethod($expr,$class,$package)) return $a;
  3512. if ($a = $this->getLinkConst($expr,$class,$package)) return $a;
  3513. if ($a = $this->getLinkVar('$'.$expr,$class,$package)) return $a;
  3514. }
  3515. if (strpos($expr,'()')) if ($a = $this->getLinkMethod($expr,$class,$package)) return $a;
  3516. if (is_numeric(strpos($expr,'$'))) if ($a = $this->getLinkVar($expr,$class,$package)) return $a;
  3517. }
  3518. }
  3519. if ($test = Converter::getClassLink(trim(str_replace('object ','',$expr)),$package)) return $test;
  3520. if ($test = Converter::getPageLink(trim($expr),$package)) return $test;
  3521. if ($test = Converter::getDefineLink(trim($expr),$package)) return $test;
  3522. if ($test = Converter::getGlobalLink(trim($expr),$package)) return $test;
  3523. // if (strpos($expr,'.'))
  3524. // package specified
  3525. if (!is_array($packages))
  3526. {
  3527. $packages = $this->all_packages;
  3528. }
  3529. do
  3530. {
  3531. if (isset($packages[$package])) unset($packages[$package]);
  3532. if ($test = Converter::getClassLink(str_replace('object ','',$expr),$package)) return $test;
  3533. if ($test = Converter::getPageLink($expr,$package)) return $test;
  3534. if ($test = Converter::getDefineLink($expr,$package)) return $test;
  3535. if ($test = Converter::getGlobalLink($expr,$package)) return $test;
  3536. // is $expr in class::method() or class::$variable format?
  3537. if (strpos($expr,'function ') === 0)
  3538. { // asking for a function, not a method
  3539. if ($test = Converter::getFunctionLink(str_replace('function','',str_replace('()','',$expr)), $package)) return $test;
  3540. else return $expr;
  3541. }
  3542. $test = $this->_getDoubleColon($expr, $package, $packages, $class, $links);
  3543. if (!is_string($test)) return $test;
  3544. if (strpos($test, 'parent::') === 0) return $test;
  3545. // $expr does not have ::
  3546. if (is_numeric(@strpos('$',$expr)))
  3547. {
  3548. // default to current class, whose name is contained in $this->render->parent
  3549. if ($test = Converter::getVarLink($expr, $class, $package)) return $test;
  3550. }
  3551. // $expr is a function? (non-method)
  3552. if (@strpos($expr,'()'))
  3553. {
  3554. // otherwise, see if it is a method
  3555. if ($class)
  3556. {
  3557. if ($test = Converter::getMethodLink(str_replace('()','',$expr), $class, $package)) return $test;
  3558. }
  3559. // extract the function name, use it to retrieve the file that the function is in
  3560. // $page = $this->func_page[str_replace('function ','',str_replace('()','',$expr))];
  3561. // return the link
  3562. if ($test = Converter::getFunctionLink(str_replace('function ','',str_replace('()','',$expr)), $package)) return $test;
  3563. }
  3564. // $expr is just a word. First, test to see if it is a function of the current package
  3565. if ($test = Converter::getFunctionLink(str_replace('function ','',str_replace('()','',$expr)), $package)) return $test;
  3566. // try other packages
  3567. // look in parent package first, if found
  3568. if (isset($this->package_parents[$package]) && in_array($this->package_parents[$package], $packages))
  3569. {
  3570. $p1 = $package;
  3571. $package = $this->package_parents[$package];
  3572. if ($package)
  3573. {
  3574. if (isset($packages[$package])) unset($packages[$package]);
  3575. }
  3576. continue;
  3577. }
  3578. // no parent package, so start with the first one that's left
  3579. $package = @array_shift(@array_keys($packages));
  3580. if ($package && isset($packages[$package]))
  3581. {
  3582. unset($packages[$package]);
  3583. }
  3584. } while (count($packages) || $package);
  3585. $funcs = get_defined_functions();
  3586. // feature 564991, link to php manual
  3587. if (in_array(str_replace(array('(',')'),array('',''),$expr),$funcs['internal']))
  3588. {
  3589. $return = 'http://www.php.net/'.str_replace(array('(',')'),array('',''),$expr);
  3590. return $return;
  3591. }
  3592. // no links found
  3593. return $expr;
  3594. }
  3595. /**
  3596. * Split up getLink to make it easier to debug
  3597. * @access private
  3598. */
  3599. function _getDoubleColon(&$expr, &$package, &$packages, $class, $links)
  3600. {
  3601. if (@strpos($expr,'::'))
  3602. {
  3603. $class_method = explode('::',$expr);
  3604. if ($class_method[0] == 'parent')
  3605. {
  3606. // can only have parent in the same package as the class! subtle bug
  3607. $package = $this->package;
  3608. $packages = array();
  3609. $cl = $this->classes->getClassByPackage($class,$package);
  3610. if (!$cl)
  3611. { // this is possible if an example file has parent::method()
  3612. return $expr;
  3613. }
  3614. $par = $cl->getParent($this);
  3615. $phpparent = false;
  3616. if (is_object($par))
  3617. {
  3618. $package = $par->docblock->package;
  3619. $phpparent = $par->getName();
  3620. } else
  3621. {
  3622. addWarning(PDERROR_CLASS_PARENT_NOT_FOUND,$class,$package,$class_method[1]);
  3623. return $expr;
  3624. }
  3625. if ($phpparent) $class_method[0] = $phpparent;
  3626. }
  3627. if (strpos($class_method[1],'()'))
  3628. {
  3629. // strip everything but the function name, return a link
  3630. if ($test = Converter::getMethodLink(str_replace('()','',$class_method[1]), $class_method[0], $package)) return $test;
  3631. }
  3632. if ($test = Converter::getVarLink($class_method[1], $class_method[0], $package)) return $test;
  3633. if ($test = Converter::getConstLink($class_method[1], $class_method[0], $package)) return $test;
  3634. }
  3635. return $expr;
  3636. }
  3637. /**
  3638. * cycle through parent classes to retrieve a link to a method
  3639. * do not use or override, used by getLink
  3640. * @access private
  3641. */
  3642. function &getLinkMethod($expr, $class, $package)
  3643. {
  3644. $links = &$this->links;
  3645. do
  3646. {
  3647. // is $expr in class::method() or class::$variable format?
  3648. if (@strpos($expr,'::'))
  3649. {
  3650. $class_method = explode('::',$expr);
  3651. if ($class_method[0] == 'parent')
  3652. {
  3653. $cl = $this->classes->getClassByPackage($class,$package);
  3654. $par = $cl->getParent($this);
  3655. $phpparent = false;
  3656. if (is_object($par))
  3657. {
  3658. $package = $par->docblock->package;
  3659. $phpparent = $par->getName();
  3660. } else addWarning(PDERROR_CLASSPARENT_NOTFOUND,$class,$package,$class_method[1]);
  3661. if ($phpparent) $class_method[0] = $phpparent;
  3662. } else
  3663. {
  3664. $cl = $this->classes->getClassByPackage($class,$package);
  3665. }
  3666. if (strpos($class_method[1],'()'))
  3667. {
  3668. // strip everything but the function name, return a link
  3669. if ($test = Converter::getMethodLink(str_replace('function ','',str_replace('()','',$class_method[1])), $class_method[0], $package)) return $test;
  3670. }
  3671. }
  3672. if ($test = Converter::getMethodLink(str_replace('()','',$expr), $class, $package)) return $test;
  3673. $cl = $this->classes->getClassByPackage($class,$package);
  3674. if ($cl)
  3675. {
  3676. $par = $cl->getParent($this);
  3677. if (is_object($par))
  3678. {
  3679. $package = $par->docblock->package;
  3680. $class = $par->getName();
  3681. } else $class = $par;
  3682. } else $class = false;
  3683. } while ($class);
  3684. // no links found
  3685. $flag = false;
  3686. return $flag;
  3687. }
  3688. /**
  3689. * cycle through parent classes to retrieve a link to a var
  3690. * do not use or override, used by getLink
  3691. * @access private
  3692. */
  3693. function &getLinkVar($expr, $class, $package)
  3694. {
  3695. $links = &$this->links;
  3696. do
  3697. {
  3698. // is $expr in class::method() or class::$variable format?
  3699. if (@strpos($expr,'::'))
  3700. {
  3701. $class_method = explode('::',$expr);
  3702. if ($class_method[0] == 'parent')
  3703. {
  3704. $cl = $this->classes->getClassByPackage($class,$package);
  3705. $phpparent = false;
  3706. $par = $cl->getParent($this);
  3707. if (is_object($par))
  3708. {
  3709. $package = $par->docblock->package;
  3710. $phpparent = $par->getName();
  3711. } else addWarning(PDERROR_CLASSPARENT_NOTFOUND,$class,$package,$class_method[1]);
  3712. if ($phpparent) $class_method[0] = $phpparent;
  3713. } else
  3714. {
  3715. $cl = $this->classes->getClassByPackage($class,$package);
  3716. }
  3717. if ($test = Converter::getVarLink($class_method[1], $class_method[0], $package)) return $test;
  3718. if ($test = Converter::getVarLink('$'.$class_method[1], $class_method[0], $package)) return $test;
  3719. }
  3720. if ($test = Converter::getVarLink($expr, $class, $package)) return $test;
  3721. if ($test = Converter::getVarLink('$'.$expr, $class, $package)) return $test;
  3722. $cl = $this->classes->getClassByPackage($class,$package);
  3723. if ($cl)
  3724. {
  3725. $par = $cl->getParent($this);
  3726. if (is_object($par))
  3727. {
  3728. $package = $par->docblock->package;
  3729. $class = $par->getName();
  3730. } else $class = $par;
  3731. } else $class = false;
  3732. } while ($class);
  3733. // no links found
  3734. $class = false;
  3735. return $class;
  3736. }
  3737. /**
  3738. * cycle through parent classes to retrieve a link to a class constant
  3739. * do not use or override, used by getLink
  3740. * @access private
  3741. * @since 1.2.4
  3742. */
  3743. function &getLinkConst($expr, $class, $package)
  3744. {
  3745. $links = &$this->links;
  3746. do
  3747. {
  3748. // is $expr in class::method() or class::$variable format?
  3749. if (@strpos($expr,'::'))
  3750. {
  3751. $class_method = explode('::',$expr);
  3752. if ($class_method[0] == 'parent')
  3753. {
  3754. $cl = $this->classes->getClassByPackage($class,$package);
  3755. $phpparent = false;
  3756. $par = $cl->getParent($this);
  3757. if (is_object($par))
  3758. {
  3759. $package = $par->docblock->package;
  3760. $phpparent = $par->getName();
  3761. } else addWarning(PDERROR_CLASSPARENT_NOTFOUND,$class,$package,$class_method[1]);
  3762. if ($phpparent) $class_method[0] = $phpparent;
  3763. } else
  3764. {
  3765. $cl = $this->classes->getClassByPackage($class,$package);
  3766. }
  3767. if ($test = Converter::getConstLink($class_method[1], $class_method[0], $package)) return $test;
  3768. }
  3769. if ($test = Converter::getConstLink($expr, $class, $package)) return $test;
  3770. $cl = $this->classes->getClassByPackage($class,$package);
  3771. if ($cl)
  3772. {
  3773. $par = $cl->getParent($this);
  3774. if (is_object($par))
  3775. {
  3776. $package = $par->docblock->package;
  3777. $class = $par->getName();
  3778. } else $class = $par;
  3779. } else $class = false;
  3780. } while ($class);
  3781. // no links found
  3782. $flag = false;
  3783. return $flag;
  3784. }
  3785. /**
  3786. * take URL $link and text $text and return a link in the format needed for the Converter
  3787. * @param string URL
  3788. * @param string text to display
  3789. * @return string link to $link
  3790. * @abstract
  3791. */
  3792. function returnLink($link,$text)
  3793. {
  3794. }
  3795. /**
  3796. * take {@link abstractLink} descendant and text $eltext and return a link
  3797. * in the format needed for the Converter
  3798. * @param abstractLink
  3799. * @param string
  3800. * @return string link to $element
  3801. * @abstract
  3802. */
  3803. function returnSee(&$link, $eltext = false)
  3804. {
  3805. }
  3806. /**
  3807. * take {@link abstractLink} descendant and text $eltext and return a
  3808. * unique ID in the format needed for the Converter
  3809. * @param abstractLink
  3810. * @return string unique identifier of $element
  3811. * @abstract
  3812. */
  3813. function getId(&$link)
  3814. {
  3815. }
  3816. /**
  3817. * Convert README/INSTALL/CHANGELOG file contents to output format
  3818. * @param README|INSTALL|CHANGELOG
  3819. * @param string contents of the file
  3820. * @abstract
  3821. */
  3822. function Convert_RIC($name, $contents)
  3823. {
  3824. }
  3825. /**
  3826. * Convert all elements to output format
  3827. *
  3828. * This will call ConvertXxx where Xxx is {@link ucfirst}($element->type).
  3829. * It is expected that a child converter defines a handler for every
  3830. * element type, even if that handler does nothing. phpDocumentor will
  3831. * terminate with an error if a handler doesn't exist.
  3832. * {@internal
  3833. * Since 1.2.0 beta 3, this function has been moved from child converters
  3834. * to the parent, because it doesn't really make sense to put it in the
  3835. * child converter, and we can add error handling.
  3836. *
  3837. * {@source}}}
  3838. * @throws {@link PDERROR_NO_CONVERT_HANDLER}
  3839. * @param mixed {@link parserElement} descendant or {@link parserPackagePage} or {@link parserData}
  3840. */
  3841. function Convert(&$element)
  3842. {
  3843. $handler = 'convert'.ucfirst($element->type);
  3844. if (method_exists($this,$handler))
  3845. {
  3846. $this->$handler($element);
  3847. } else
  3848. {
  3849. addErrorDie(PDERROR_NO_CONVERTER_HANDLER,$element->type,$handler,phpDocumentor_get_class($this));
  3850. }
  3851. }
  3852. /**#@+
  3853. * Conversion Handlers
  3854. *
  3855. * All of the convert* handlers set up template variables for the Smarty
  3856. * template.{@internal In addition, the {@link newSmarty()} method is
  3857. * called to retrieve the global Smarty template}}
  3858. */
  3859. /**
  3860. * Default Tutorial Handler
  3861. *
  3862. * Sets up the tutorial template, and its prev/next/parent links
  3863. * {@internal
  3864. * Retrieves the title using {@link parserTutorial::getTitle()} and uses the
  3865. * {@link parserTutorial::prev, parserTutorial::next, parserTutorial::parent}
  3866. * links to set up those links.}}
  3867. * @param parserTutorial
  3868. */
  3869. function &convertTutorial(&$element)
  3870. {
  3871. $this->package = $element->package;
  3872. $this->subpackage = $element->subpackage;
  3873. $x = $element->Convert($this);
  3874. $template = &$this->newSmarty();
  3875. $template->assign('contents',$x);
  3876. $template->assign('title',$element->getTitle($this));
  3877. $template->assign('nav',$element->parent || $element->prev || $element->next);
  3878. if ($element->parent)
  3879. {
  3880. $template->assign('up',$this->getId($element->parent));
  3881. $template->assign('uptitle',$element->parent->title);
  3882. }
  3883. if ($element->prev)
  3884. {
  3885. $template->assign('prev',$this->getId($element->prev));
  3886. $template->assign('prevtitle',$element->prev->title);
  3887. }
  3888. if ($element->next)
  3889. {
  3890. $template->assign('next',$this->getId($element->next));
  3891. $template->assign('nexttitle',$element->next->title);
  3892. }
  3893. return $template;
  3894. }
  3895. /**
  3896. * Default Class Handler
  3897. *
  3898. * Sets up the class template.
  3899. * {@internal special methods
  3900. * {@link generateChildClassList(), generateFormattedClassTree()},
  3901. * {@link getFormattedConflicts, getFormattedInheritedMethods},
  3902. * and {@link getFormattedInheritedVars} are called to complete vital
  3903. * template setup.}}
  3904. */
  3905. function convertClass(&$element)
  3906. {
  3907. $this->class = $element->getName();
  3908. $this->class_data = &$this->newSmarty();
  3909. $this->class_data->assign("class_name",$element->getName());
  3910. $this->class_data->assign("vars",array());
  3911. $this->class_data->assign("methods",array());
  3912. $this->class_data->assign("consts",array());
  3913. $this->class_data->assign("is_interface", $element->isInterface());
  3914. $this->class_data->assign("implements", $this->getFormattedImplements($element));
  3915. $this->class_data->assign("package",$element->docblock->package);
  3916. $this->class_data->assign("line_number",$element->getLineNumber());
  3917. $this->class_data->assign("source_location",$element->getSourceLocation($this));
  3918. $this->class_data->assign("page_link",$this->getCurrentPageLink());
  3919. $docblock = $this->prepareDocBlock($element, false);
  3920. $this->class_data->assign("sdesc",$docblock['sdesc']);
  3921. $this->class_data->assign("desc",$docblock['desc']);
  3922. $this->class_data->assign("access", $docblock['access']);
  3923. $this->class_data->assign("abstract", $docblock['abstract']);
  3924. $this->class_data->assign("tags",$docblock['tags']);
  3925. $this->class_data->assign("api_tags",$docblock['api_tags']);
  3926. $this->class_data->assign("info_tags",$docblock['info_tags']);
  3927. $this->class_data->assign("utags",$docblock['utags']);
  3928. $this->class_data->assign( "prop_tags", $docblock['property_tags'] );
  3929. if ($this->hasSourceCode($element->getPath())) {
  3930. $this->class_data->assign("class_slink",$this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true));
  3931. }
  3932. else
  3933. $this->class_data->assign("class_slink",false);
  3934. $this->class_data->assign("children", $this->generateChildClassList($element));
  3935. $this->class_data->assign("class_tree", $this->generateFormattedClassTree($element));
  3936. $this->class_data->assign("conflicts", $this->getFormattedConflicts($element,"classes"));
  3937. $inherited_methods = $this->getFormattedInheritedMethods($element);
  3938. if (!empty($inherited_methods))
  3939. {
  3940. $this->class_data->assign("imethods",$inherited_methods);
  3941. } else
  3942. {
  3943. $this->class_data->assign("imethods",false);
  3944. }
  3945. $inherited_vars = $this->getFormattedInheritedVars($element);
  3946. if (!empty($inherited_vars))
  3947. {
  3948. $this->class_data->assign("ivars",$inherited_vars);
  3949. } else
  3950. {
  3951. $this->class_data->assign("ivars",false);
  3952. }
  3953. $inherited_consts = $this->getFormattedInheritedConsts($element);
  3954. if (!empty($inherited_consts))
  3955. {
  3956. $this->class_data->assign("iconsts",$inherited_consts);
  3957. } else
  3958. {
  3959. $this->class_data->assign("iconsts",false);
  3960. }
  3961. }
  3962. /**
  3963. * Converts method for template output
  3964. *
  3965. * This function must be called by a child converter with any extra
  3966. * template variables needed in the parameter $addition
  3967. * @param parserMethod
  3968. */
  3969. function convertMethod(&$element, $additions = array())
  3970. {
  3971. $fname = $element->getName();
  3972. $docblock = $this->prepareDocBlock($element);
  3973. $returntype = 'void';
  3974. if ($element->isConstructor) $returntype = $element->class;
  3975. if ($element->docblock->return)
  3976. {
  3977. $a = $element->docblock->return->Convert($this);
  3978. $returntype = $element->docblock->return->converted_returnType;
  3979. }
  3980. $params = $param_i = array();
  3981. if (count($element->docblock->params))
  3982. foreach($element->docblock->params as $param => $val)
  3983. {
  3984. $a = $val->Convert($this);
  3985. $params[] = $param_i[$param] = array("var" => $param,"datatype" => $val->converted_returnType,"data" => $a);
  3986. }
  3987. if ($element->docblock->hasaccess) {
  3988. $acc = $docblock['access'];
  3989. } else {
  3990. $acc = 'public';
  3991. }
  3992. if ($this->hasSourceCode($element->getPath()))
  3993. $additions["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  3994. $this->class_data->append('methods',array_merge(
  3995. array('sdesc' => $docblock['sdesc'],
  3996. 'desc' => $docblock['desc'],
  3997. 'static' => $docblock['static'],
  3998. 'abstract' => $docblock['abstract'],
  3999. 'tags' => $docblock['tags'],
  4000. 'api_tags' => $docblock['api_tags'],
  4001. 'see_tags' => $docblock['see_tags'],
  4002. 'info_tags_sorted' => $docblock['info_tags_sorted'],
  4003. 'info_tags' => $docblock['info_tags'],
  4004. 'utags' => $docblock['utags'],
  4005. 'constructor' => $element->isConstructor,
  4006. 'access' => $acc,
  4007. 'function_name' => $fname,
  4008. 'function_return' => $returntype,
  4009. 'function_call' => $element->getFunctionCall(),
  4010. 'ifunction_call' => $element->getIntricateFunctionCall($this, $param_i),
  4011. 'descmethod' => $this->getFormattedDescMethods($element),
  4012. 'method_overrides' => $this->getFormattedOverrides($element),
  4013. 'method_implements' => $this->getFormattedMethodImplements($element),
  4014. 'line_number' => $element->getLineNumber(),
  4015. 'id' => $this->getId($element),
  4016. 'params' => $params),
  4017. $additions));
  4018. }
  4019. /**
  4020. * Converts class variables for template output.
  4021. *
  4022. * This function must be called by a child converter with any extra
  4023. * template variables needed in the parameter $addition
  4024. * @param parserVar
  4025. */
  4026. function convertVar(&$element, $additions = array())
  4027. {
  4028. $docblock = $this->prepareDocBlock($element);
  4029. $b = 'mixed';
  4030. if ($element->docblock->hasaccess)
  4031. $acc = $element->docblock->tags['access'][0]->value;
  4032. else
  4033. $acc = 'public';
  4034. if ($element->docblock->var)
  4035. {
  4036. $b = $element->docblock->var->converted_returnType;
  4037. }
  4038. if ($this->hasSourceCode($element->getPath()))
  4039. $additions["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  4040. $this->class_data->append('vars',array_merge(
  4041. array('sdesc' => $docblock['sdesc'],
  4042. 'desc' => $docblock['desc'],
  4043. 'static' => $docblock['static'],
  4044. 'abstract' => $docblock['abstract'],
  4045. 'utags' => $docblock['utags'],
  4046. 'tags' => $docblock['tags'],
  4047. 'api_tags' => $docblock['api_tags'],
  4048. 'info_tags' => $docblock['info_tags'],
  4049. 'var_name' => $element->getName(),
  4050. 'has_default' => strlen($element->getValue()),
  4051. 'var_default' => $this->postProcess($element->getValue()),
  4052. 'var_type' => $b,
  4053. 'access' => $acc,
  4054. 'line_number' => $element->getLineNumber(),
  4055. 'descvar' => $this->getFormattedDescVars($element),
  4056. 'var_overrides' => $this->getFormattedOverrides($element),
  4057. 'id' => $this->getId($element)),
  4058. $additions));
  4059. }
  4060. /**
  4061. * Converts class constants for template output.
  4062. *
  4063. * This function must be called by a child converter with any extra
  4064. * template variables needed in the parameter $addition
  4065. * @param parserConst
  4066. */
  4067. function convertConst(&$element, $additions = array())
  4068. {
  4069. $docblock = $this->prepareDocBlock($element);
  4070. if ($element->docblock->hasaccess)
  4071. $acc = $element->docblock->tags['access'][0]->value;
  4072. else
  4073. $acc = 'public';
  4074. if ($this->hasSourceCode($element->getPath()))
  4075. $additions["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  4076. $this->class_data->append('consts',array_merge(
  4077. array('sdesc' => $docblock['sdesc'],
  4078. 'desc' => $docblock['desc'],
  4079. 'access' => $docblock['access'],
  4080. 'abstract' => $docblock['abstract'],
  4081. 'utags' => $docblock['utags'],
  4082. 'tags' => $docblock['tags'],
  4083. 'api_tags' => $docblock['api_tags'],
  4084. 'info_tags' => $docblock['info_tags'],
  4085. 'const_name' => $element->getName(),
  4086. 'const_value' => $this->postProcess($element->getValue()),
  4087. 'access' => $acc,
  4088. 'line_number' => $element->getLineNumber(),
  4089. 'id' => $this->getId($element)),
  4090. $additions));
  4091. }
  4092. /**
  4093. * Default Page Handler
  4094. *
  4095. * {@internal In addition to setting up the smarty template with {@link newSmarty()},
  4096. * this class uses {@link getSourceLocation()} and {@link getClassesOnPage()}
  4097. * to set template variables. Also used is {@link getPageName()}, to get
  4098. * a Converter-specific name for the page.}}
  4099. * @param parserPage
  4100. */
  4101. function convertPage(&$element)
  4102. {
  4103. $this->page_data = &$this->newSmarty(true);
  4104. $this->page = $this->getPageName($element->parent);
  4105. $this->path = $element->parent->getPath();
  4106. $this->curpage = &$element->parent;
  4107. $this->page_data->assign("source_location",$element->parent->getSourceLocation($this));
  4108. $this->page_data->assign("functions",array());
  4109. $this->page_data->assign("includes",array());
  4110. $this->page_data->assign("defines",array());
  4111. $this->page_data->assign("globals",array());
  4112. $this->page_data->assign("classes",$this->getClassesOnPage($element));
  4113. $this->page_data->assign("hasclasses",$element->hasClasses());
  4114. $this->page_data->assign("hasinterfaces",$element->hasInterfaces());
  4115. $this->page_data->assign("name", $element->parent->getFile());
  4116. if ($t = $element->getTutorial())
  4117. {
  4118. $this->page_data->assign("tutorial",$this->returnSee($t));
  4119. } else
  4120. {
  4121. $this->page_data->assign("tutorial",false);
  4122. }
  4123. if ($element->docblock)
  4124. {
  4125. $docblock = $this->prepareDocBlock($element, false);
  4126. $this->page_data->assign("sdesc",$docblock['sdesc']);
  4127. $this->page_data->assign("desc",$docblock['desc']);
  4128. $this->page_data->assign("tags",$docblock['tags']);
  4129. $this->page_data->assign("api_tags",$docblock['api_tags']);
  4130. $this->page_data->assign("info_tags",$docblock['info_tags']);
  4131. $this->page_data->assign("utags",$docblock['utags']);
  4132. }
  4133. }
  4134. /**
  4135. * Converts global variables for template output
  4136. *
  4137. * This function must be called by a child converter with any extra
  4138. * template variables needed in the parameter $addition
  4139. * {@internal
  4140. * In addition to using {@link prepareDocBlock()}, this method also
  4141. * uses utility functions {@link getGlobalValue(), getFormattedConflicts()}}}
  4142. * @param parserGlobal
  4143. * @uses postProcess() on global_value template value, makes it displayable
  4144. * @param array any additional template variables should be in this array
  4145. */
  4146. function convertGlobal(&$element, $addition = array())
  4147. {
  4148. $docblock = $this->prepareDocBlock($element);
  4149. $value = $this->getGlobalValue($element->getValue());
  4150. if ($this->hasSourceCode($element->getPath()))
  4151. $addition["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  4152. $this->page_data->append('globals',array_merge(
  4153. array('sdesc' => $docblock['sdesc'],
  4154. 'desc' => $docblock['desc'],
  4155. 'tags' => $docblock['tags'],
  4156. 'api_tags' => $docblock['api_tags'],
  4157. 'info_tags' => $docblock['info_tags'],
  4158. 'utags' => $docblock['utags'],
  4159. 'global_name' => $element->getName(),
  4160. 'global_type' => $element->getDataType($this),
  4161. 'global_value' => $value,
  4162. 'line_number' => $element->getLineNumber(),
  4163. 'global_conflicts' => $this->getFormattedConflicts($element,"global variables"),
  4164. 'id' => $this->getId($element)),
  4165. $addition));
  4166. }
  4167. /**
  4168. * Converts defines for template output
  4169. *
  4170. * This function must be called by a child converter with any extra
  4171. * template variables needed in the parameter $addition
  4172. * {@internal
  4173. * In addition to using {@link prepareDocBlock()}, this method also
  4174. * uses utility functions {@link getGlobalValue(), getFormattedConflicts()}}}
  4175. * @param parserDefine
  4176. * @uses postProcess() on define_value template value, makes it displayable
  4177. * @param array any additional template variables should be in this array
  4178. */
  4179. function convertDefine(&$element, $addition = array())
  4180. {
  4181. $docblock = $this->prepareDocBlock($element);
  4182. if ($this->hasSourceCode($element->getPath()))
  4183. $addition["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  4184. $this->page_data->append('defines',array_merge(
  4185. array('sdesc' => $docblock['sdesc'],
  4186. 'desc' => $docblock['desc'],
  4187. 'tags' => $docblock['tags'],
  4188. 'api_tags' => $docblock['api_tags'],
  4189. 'info_tags' => $docblock['info_tags'],
  4190. 'utags' => $docblock['utags'],
  4191. 'define_name' => $element->getName(),
  4192. 'line_number' => $element->getLineNumber(),
  4193. 'define_value' => $this->postProcess($element->getValue()),
  4194. 'define_conflicts' => $this->getFormattedConflicts($element,"defines"),
  4195. 'id' => $this->getId($element)),
  4196. $addition));
  4197. }
  4198. /**
  4199. * Converts includes for template output
  4200. *
  4201. * This function must be called by a child converter with any extra
  4202. * template variables needed in the parameter $addition
  4203. * @see prepareDocBlock()
  4204. * @param parserInclude
  4205. */
  4206. function convertInclude(&$element, $addition = array())
  4207. {
  4208. $docblock = $this->prepareDocBlock($element);
  4209. $per = $this->getIncludeValue($element->getValue(), $element->getPath());
  4210. if ($this->hasSourceCode($element->getPath()))
  4211. $addition["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  4212. $this->page_data->append('includes',array_merge(
  4213. array('sdesc' => $docblock['sdesc'],
  4214. 'desc' => $docblock['desc'],
  4215. 'tags' => $docblock['tags'],
  4216. 'api_tags' => $docblock['api_tags'],
  4217. 'info_tags' => $docblock['info_tags'],
  4218. 'utags' => $docblock['utags'],
  4219. 'include_name' => $element->getName(),
  4220. 'line_number' => $element->getLineNumber(),
  4221. 'include_value' => $per),
  4222. $addition));
  4223. }
  4224. /**
  4225. * Converts function for template output
  4226. *
  4227. * This function must be called by a child converter with any extra
  4228. * template variables needed in the parameter $addition
  4229. * @see prepareDocBlock()
  4230. * @param parserFunction
  4231. */
  4232. function convertFunction(&$element, $addition = array())
  4233. {
  4234. $docblock = $this->prepareDocBlock($element);
  4235. $fname = $element->getName();
  4236. $params = $param_i = array();
  4237. if (count($element->docblock->params))
  4238. foreach($element->docblock->params as $param => $val)
  4239. {
  4240. $a = $val->Convert($this);
  4241. $params[] = $param_i[$param] = array("var" => $param,"datatype" => $val->converted_returnType,"data" => $a);
  4242. }
  4243. $returntype = 'void';
  4244. if ($element->docblock->return)
  4245. {
  4246. $a = $element->docblock->return->Convert($this);
  4247. $returntype = $element->docblock->return->converted_returnType;
  4248. }
  4249. if ($this->hasSourceCode($element->getPath()))
  4250. $addition["slink"] = $this->getSourceAnchor($element->getPath(),$element->getLineNumber(),$element->getLineNumber(),true);
  4251. $this->page_data->append('functions',array_merge(
  4252. array('sdesc' => $docblock['sdesc'],
  4253. 'desc' => $docblock['desc'],
  4254. 'tags' => $docblock['tags'],
  4255. 'api_tags' => $docblock['api_tags'],
  4256. 'info_tags' => $docblock['info_tags'],
  4257. 'utags' => $docblock['utags'],
  4258. 'function_name' => $fname,
  4259. 'function_return' => $returntype,
  4260. 'function_conflicts' => $this->getFormattedConflicts($element,"functions"),
  4261. 'ifunction_call' => $element->getIntricateFunctionCall($this, $param_i),
  4262. 'function_call' => $element->getFunctionCall(),
  4263. 'line_number' => $element->getLineNumber(),
  4264. 'id' => $this->getId($element),
  4265. 'params' => $params),
  4266. $addition));
  4267. }
  4268. /**#@-*/
  4269. /**
  4270. * convert the element's DocBlock for output
  4271. *
  4272. * This function converts all tags and descriptions for output
  4273. * @param mixed any descendant of {@link parserElement}, or {@link parserData}
  4274. * @param array used to translate tagnames into other tags
  4275. * @param boolean set to false for pages and classes, the only elements allowed to specify @package
  4276. * @return array
  4277. *
  4278. * Format:
  4279. * <pre>
  4280. * array('sdesc' => DocBlock summary
  4281. * 'desc' => DocBlock detailed description
  4282. * 'tags' => array('keyword' => tagname, 'data' => tag description)
  4283. * known tags
  4284. * 'api_tags' => array('keyword' => tagname, 'data' => tag description)
  4285. * known api documentation tags
  4286. * 'info_tags' => array('keyword' => tagname, 'data' => tag description)
  4287. * known informational tags
  4288. * [ 'utags' => array('keyword' => tagname, 'data' => tag description
  4289. * unknown tags ]
  4290. * [ 'vartype' => type from @var/@return tag ]
  4291. * [ 'var_descrip' => description from @var/@return tag ]
  4292. * )
  4293. * </pre>
  4294. */
  4295. function prepareDocBlock(&$element, $names = array(),$nopackage = true)
  4296. {
  4297. $tagses = $element->docblock->listTags();
  4298. $tags = $ret = $api_tags = $info_tags = array();
  4299. $api_tags_arr = array("abstract", "access", "deprecated", "example", "filesource",
  4300. "global", "internal", "name", "return", "see",
  4301. "property", "property-read", "property-write", "method",
  4302. "staticvar", "usedby", "uses", "var");
  4303. if (!$nopackage)
  4304. {
  4305. $tags[] = array('keyword' => 'package','data' => $element->docblock->package);
  4306. if (!empty($element->docblock->subpackage)) $tags[] = array('keyword' => 'subpackage','data' => $element->docblock->subpackage);
  4307. }
  4308. if ($element->docblock->var)
  4309. {
  4310. $a = $element->docblock->var->Convert($this);
  4311. $ret['vartype'] = $element->docblock->var->converted_returnType;
  4312. if (!empty($a))
  4313. {
  4314. $tags[] = array('keyword' => 'var', 'data' => $a);
  4315. $ret["var_descrip"] = $a;
  4316. }
  4317. }
  4318. if ($element->docblock->return)
  4319. {
  4320. $a = $element->docblock->return->Convert($this);
  4321. $ret['vartype'] = $element->docblock->return->converted_returnType;
  4322. if (!empty($a))
  4323. {
  4324. $tags[] = $api_tags[] = array('keyword' => 'return', 'data' => $a);
  4325. $ret["var_descrip"] = $a;
  4326. }
  4327. }
  4328. if ($element->docblock->funcglobals)
  4329. foreach($element->docblock->funcglobals as $global => $val)
  4330. {
  4331. if ($a = $this->getGlobalLink($global,$element->docblock->package))
  4332. {
  4333. $global = $a;
  4334. }
  4335. $b = Converter::getLink($val[0]);
  4336. if (is_object($b) && phpDocumentor_get_class($b) == 'classlink')
  4337. {
  4338. $val[0] = $this->returnSee($b);
  4339. }
  4340. $tags[] = $api_tags[] = array('keyword' => 'global','data' => $val[0].' '.$global.': '.$val[1]->Convert($this));
  4341. }
  4342. if ($element->docblock->statics)
  4343. foreach($element->docblock->statics as $static => $val)
  4344. {
  4345. $a = $val->Convert($this);
  4346. $tags[] = $api_tags[] = array('keyword' => 'staticvar','data' => $val->converted_returnType.' '.$static.': '.$a);
  4347. }
  4348. $property_tags = array();
  4349. foreach ( $element->docblock->properties as $prop_name => $val )
  4350. {
  4351. $a = $val->Convert( $this );
  4352. if ( !empty( $a ) )
  4353. {
  4354. $tags[] = $api_tags[] = array( 'keyword' => $val->keyword ,
  4355. 'data' => $val->converted_returnType . ' ' . $prop_name . ': ' . $a );
  4356. $prop['prop_name'] = $prop_name;
  4357. $prop['access'] = $val->keyword == 'property-read' ? 'read' :
  4358. ( $val->keyword == 'property-write' ? 'write' : 'read/write' );
  4359. $prop['prop_type'] = $val->converted_returnType;
  4360. $prop['sdesc'] = $a;
  4361. $property_tags[ $prop_name ] = $prop;
  4362. }
  4363. }
  4364. ksort( $property_tags, SORT_STRING );
  4365. $property_tags = array_values( $property_tags );
  4366. $info_tags_sorted = array();
  4367. $ret['static'] = false;
  4368. foreach($tagses as $tag)
  4369. {
  4370. if (isset($names[$tag->keyword])) $tag->keyword = $names[$tag->keyword];
  4371. if ($tag->keyword == 'static') {
  4372. $ret['static'] = true;
  4373. continue;
  4374. }
  4375. if ($tag->keyword)
  4376. $tags[] = array("keyword" => $tag->keyword,"data" => $tag->Convert($this));
  4377. if (in_array($tag->keyword, $api_tags_arr)) {
  4378. $api_tags[] = array("keyword" => $tag->keyword,"data" => $tag->Convert($this));
  4379. } else {
  4380. $info_tags[] = array("keyword" => $tag->keyword,"data" => $tag->Convert($this));
  4381. @list( $className, $desc ) = explode( " ", $tag->Convert($this), 2 );
  4382. $info_tags_sorted[ $tag->keyword ][] = array( 'keyword' => $className, 'data' => $desc );
  4383. }
  4384. }
  4385. $utags = array();
  4386. foreach($element->docblock->unknown_tags as $keyword => $tag)
  4387. {
  4388. foreach($tag as $t)
  4389. $utags[] = array('keyword' => $keyword, 'data' => $t->Convert($this));
  4390. }
  4391. $ret['abstract'] = false;
  4392. $ret['access'] = 'public';
  4393. $see_tags = array();
  4394. foreach($tags as $tag)
  4395. {
  4396. if ($tag['keyword'] == 'access') {
  4397. $ret['access'] = $tag['data'];
  4398. }
  4399. if ($tag['keyword'] == 'abstract') {
  4400. $ret['abstract'] = true;
  4401. }
  4402. if ($tag['keyword'] == 'see' || $tag['keyword'] == 'uses' ||
  4403. $tag['keyword'] == 'usedby') {
  4404. $see_tags[] = $tag['data'];
  4405. }
  4406. }
  4407. $ret['sdesc'] = $element->docblock->getSDesc($this);
  4408. $ret['desc'] = $element->docblock->getDesc($this);
  4409. $ret['tags'] = $tags;
  4410. $ret['see_tags'] = $see_tags;
  4411. $ret['info_tags_sorted'] = $info_tags_sorted;
  4412. $ret['api_tags'] = $api_tags;
  4413. $ret['info_tags'] = $info_tags;
  4414. $ret['utags'] = $utags;
  4415. $ret['property_tags'] = $property_tags;
  4416. return $ret;
  4417. }
  4418. /**
  4419. * gets a list of all classes declared on a procedural page represented by
  4420. * $element, a {@link parserData} class
  4421. * @param parserData &$element
  4422. * @return array links to each classes documentation
  4423. *
  4424. * Format:
  4425. * <pre>
  4426. * array('name' => class name,
  4427. * 'sdesc' => summary of the class
  4428. * 'link' => link to the class's documentation)
  4429. * </pre>
  4430. */
  4431. function getClassesOnPage(&$element)
  4432. {
  4433. global $_phpDocumentor_setting;
  4434. $a = $element->getClasses($this);
  4435. $classes = array();
  4436. foreach($a as $package => $clas)
  4437. {
  4438. if (!empty($_phpDocumentor_setting['packageoutput']))
  4439. {
  4440. $packages = explode(',',$_phpDocumentor_setting['packageoutput']);
  4441. if (!in_array($package, $packages)) continue;
  4442. }
  4443. for($i=0; $i<count($clas); $i++)
  4444. {
  4445. if ($this->parseprivate || ! ($clas[$i]->docblock && $clas[$i]->docblock->hasaccess && $clas[$i]->docblock->tags['access'][0]->value == 'private'))
  4446. {
  4447. $sdesc = '';
  4448. $r = array();
  4449. $sdesc = $clas[$i]->docblock->getSDesc($this);
  4450. if ($clas[$i]->docblock->hasaccess)
  4451. $r['access'] = $clas[$i]->docblock->tags['access'][0]->value;
  4452. else
  4453. $r['access'] = 'public';
  4454. if (isset ($clas[$i]->docblock->tags['abstract']))
  4455. $r['abstract'] = TRUE;
  4456. else
  4457. $r['abstract'] = FALSE;
  4458. $r['name'] = $clas[$i]->getName();
  4459. $r['sdesc'] = $sdesc;
  4460. $r['link'] = $this->getClassLink($clas[$i]->getName(),$package,$clas[$i]->getPath());
  4461. $classes[] = $r;
  4462. }
  4463. }
  4464. }
  4465. return $classes;
  4466. }
  4467. /**
  4468. * returns an array containing the class inheritance tree from the root
  4469. * object to the class.
  4470. *
  4471. * This method must be overridden, or phpDocumentor will halt with a fatal
  4472. * error
  4473. * @return string Converter-specific class tree for an individual class
  4474. * @param parserClass class variable
  4475. * @abstract
  4476. */
  4477. function generateFormattedClassTree($class)
  4478. {
  4479. addErrorDie(PDERROR_CONVERTER_OVR_GFCT,phpDocumentor_get_class($this));
  4480. }
  4481. /**
  4482. * returns an array containing the class inheritance tree from the root
  4483. * object to the class.
  4484. *
  4485. * This method must be overridden, or phpDocumentor will halt with a fatal
  4486. * error
  4487. * @return string Converter-specific class tree for an individual class
  4488. * @param parserClass class variable
  4489. * @abstract
  4490. */
  4491. function getFormattedImplements($el)
  4492. {
  4493. $ret = array();
  4494. foreach ($el->getImplements() as $interface)
  4495. {
  4496. $link = $this->getLink($interface);
  4497. if ($link && is_object($link)) {
  4498. $ret[] = $this->returnSee($link);
  4499. } else {
  4500. if (class_exists('ReflectionClass')) {
  4501. if (interface_exists($interface)) {
  4502. $inter = new ReflectionClass($interface);
  4503. if ($inter->isInternal()) {
  4504. $ret[] = $interface . ' (internal interface)';
  4505. } else {
  4506. $ret[] = $interface;
  4507. }
  4508. }
  4509. } else {
  4510. $ret[] = $interface;
  4511. }
  4512. }
  4513. }
  4514. return $ret;
  4515. }
  4516. /**
  4517. * @param mixed {@link parserClass, parserFunction, parserDefine} or
  4518. * {@link parserGlobal}
  4519. * @param string type to display. either 'class','function','define'
  4520. * or 'global variable'
  4521. * @return array links to conflicting elements, or empty array
  4522. * @uses parserClass::getConflicts()
  4523. * @uses parserFunction::getConflicts()
  4524. * @uses parserDefine::getConflicts()
  4525. * @uses parserGlobal::getConflicts()
  4526. */
  4527. function getFormattedConflicts(&$element,$type)
  4528. {
  4529. $conflicts = $element->getConflicts($this);
  4530. $r = array();
  4531. if (!$conflicts) return false;
  4532. foreach($conflicts as $package => $class)
  4533. {
  4534. $r[] = $class->getLink($this,$class->docblock->package);
  4535. }
  4536. if (!empty($r)) $r = array('conflicttype' => $type, 'conflicts' => $r);
  4537. return $r;
  4538. }
  4539. /**
  4540. * Get a list of methods in child classes that override this method
  4541. * @return array empty array or array(array('link'=>link to method,
  4542. * 'sdesc'=>short description of the method),...)
  4543. * @uses parserMethod::getOverridingMethods()
  4544. * @param parserMethod
  4545. */
  4546. function getFormattedDescMethods(&$element)
  4547. {
  4548. $meths = $element->getOverridingMethods($this);
  4549. $r = array();
  4550. for($i=0; $i<count($meths); $i++)
  4551. {
  4552. $ms = array();
  4553. $ms['link'] = $meths[$i]->getLink($this);
  4554. $ms['sdesc'] = $meths[$i]->docblock->getSDesc($this);
  4555. $r[] = $ms;
  4556. }
  4557. return $r;
  4558. }
  4559. /**
  4560. * Get a list of vars in child classes that override this var
  4561. * @return array empty array or array('link'=>link to var,
  4562. * 'sdesc'=>short description of the method
  4563. * @uses parserVar::getOverridingVars()
  4564. * @param parserVar
  4565. */
  4566. function getFormattedDescVars(&$element)
  4567. {
  4568. $vars = $element->getOverridingVars($this);
  4569. $r = array();
  4570. for($i=0; $i<count($vars); $i++)
  4571. {
  4572. $vs = array();
  4573. $vs['link'] = $vars[$i]->getLink($this);
  4574. $vs['sdesc'] = $vars[$i]->docblock->getSDesc($this);
  4575. $r[] = $vs;
  4576. }
  4577. return $r;
  4578. }
  4579. /**
  4580. * Get the method this method overrides, if any
  4581. * @return array|false array('link'=>link to overridden method,
  4582. * 'sdesc'=>short description
  4583. * @see parserMethod::getOverrides()
  4584. * @param parserMethod
  4585. */
  4586. function getFormattedOverrides(&$element)
  4587. {
  4588. $ovr = $element->getOverrides($this);
  4589. if (!$ovr) return false;
  4590. $sdesc = $ovr->docblock->getSDesc($this);
  4591. $name = method_exists($ovr, 'getFunctionCall') ? $ovr->getFunctionCall() : $ovr->getName();
  4592. $link = ($link = $ovr->getLink($this)) ? $link : $ovr->getClass() . '::' . $name;
  4593. return array('link' => $link,'sdesc' => $sdesc);
  4594. }
  4595. /**
  4596. * Get the method this method(s) implemented from an interface, if any
  4597. * @return array|false array('link'=>link to implemented method,
  4598. * 'sdesc'=>short description
  4599. * @uses parserMethod::getImplements()
  4600. * @param parserMethod
  4601. */
  4602. function getFormattedMethodImplements(&$element)
  4603. {
  4604. $ovr = $element->getImplements($this);
  4605. if (!$ovr) return false;
  4606. $ret = array();
  4607. foreach ($ovr as $impl) {
  4608. $sdesc = $impl->docblock->getSDesc($this);
  4609. $name = $impl->getName();
  4610. $link = ($link = $impl->getLink($this)) ? $link : $impl->getClass() . '::' . $name;
  4611. $ret[] = array('link' => $link,'sdesc' => $sdesc);
  4612. }
  4613. return $ret;
  4614. }
  4615. /**
  4616. * returns a list of child classes
  4617. *
  4618. * @param parserClass class variable
  4619. * @uses parserClass::getChildClassList()
  4620. */
  4621. function generateChildClassList($class)
  4622. {
  4623. $kids = $class->getChildClassList($this);
  4624. $list = array();
  4625. if (count($kids))
  4626. {
  4627. for($i=0; $i<count($kids); $i++)
  4628. {
  4629. $lt['link'] = $kids[$i]->getLink($this);
  4630. $lt['sdesc'] = $kids[$i]->docblock->getSDesc($this);
  4631. if ($kids[$i]->docblock->hasaccess)
  4632. $lt['access'] = $kids[$i]->docblock->tags['access'][0]->value;
  4633. else
  4634. $lt['access'] = 'public';
  4635. $lt['abstract'] = isset ($kids[$i]->docblock->tags['abstract'][0]);
  4636. $list[] = $lt;
  4637. }
  4638. } else return false;
  4639. return $list;
  4640. }
  4641. /**
  4642. * Return template-enabled list of inherited variables
  4643. *
  4644. * uses parserVar helper function getInheritedVars and generates a
  4645. * template-enabled list using getClassLink()
  4646. * @param parserVar $child class var
  4647. * @see getClassLink(), parserVar::getInheritedVars()
  4648. * @return array Format:
  4649. * <pre>
  4650. * array(
  4651. * array('parent_class' => link to parent class's documentation,
  4652. * 'ivars' =>
  4653. * array(
  4654. * array('name' => inherited variable name,
  4655. * 'link' => link to inherited variable's documentation,
  4656. * 'default' => default value of inherited variable,
  4657. * 'sdesc' => summary of inherited variable),
  4658. * ...),
  4659. * ...)
  4660. * </pre>
  4661. */
  4662. function getFormattedInheritedVars($child)
  4663. {
  4664. $package = $child->docblock->package;
  4665. $subpackage = $child->docblock->subpackage;
  4666. $ivars = $child->getInheritedVars($this);
  4667. $results = array();
  4668. if (!count($ivars)) return $results;
  4669. foreach($ivars as $parent => $vars)
  4670. {
  4671. $file = $vars['file'];
  4672. $vars = $vars['vars'];
  4673. $par = $this->classes->getClass($parent,$file);
  4674. if ($par) {
  4675. $package = $par->docblock->package;
  4676. }
  4677. usort($vars,array($this,"sortVar"));
  4678. $result['parent_class'] = $this->getClassLink($parent, $package);
  4679. if (!$result['parent_class']) {
  4680. $result['parent_class'] = $parent . ' (Internal Class)';
  4681. }
  4682. foreach($vars as $var)
  4683. {
  4684. $info = array();
  4685. if ($var->docblock->hasaccess) {
  4686. $info['access'] = $var->docblock->tags['access'][0]->value;
  4687. } else {
  4688. $info['access'] = 'public';
  4689. }
  4690. $info['abstract'] = isset ($var->docblock->tags['abstract'][0]);
  4691. $info['name'] = $var->getName();
  4692. $info['link'] = $var->getLink($this);
  4693. if (!$info['link']) {
  4694. $info['link'] = $info['name'];
  4695. }
  4696. $info['default'] = $this->postProcess($var->getValue());
  4697. if ($var->docblock)
  4698. $info['sdesc'] = $var->docblock->getSDesc($this);
  4699. $result["ivars"][] = $info;
  4700. }
  4701. $results[] = $result;
  4702. $result = array();
  4703. }
  4704. return $results;
  4705. }
  4706. /**
  4707. * Return template-enabled list of inherited methods
  4708. *
  4709. * uses parserMethod helper function getInheritedMethods and generates a
  4710. * template-enabled list using getClassLink()
  4711. * @param parserMethod $child class method
  4712. * @see getClassLink(), parserMethod::getInheritedMethods()
  4713. * @return array Format:
  4714. * <pre>
  4715. * array(
  4716. * array('parent_class' => link to parent class's documentation,
  4717. * 'ivars' =>
  4718. * array(
  4719. * array('name' => inherited variable name,
  4720. * 'link' => link to inherited variable's documentation,
  4721. * 'function_call' => {@link parserMethod::getIntricateFunctionCall()}
  4722. * returned array,
  4723. * 'sdesc' => summary of inherited variable),
  4724. * ...),
  4725. * ...)
  4726. * </pre>
  4727. */
  4728. function getFormattedInheritedMethods($child)
  4729. {
  4730. $package = $child->docblock->package;
  4731. $subpackage = $child->docblock->subpackage;
  4732. $imethods = $child->getInheritedMethods($this);
  4733. $results = array();
  4734. if (!count($imethods)) return $results;
  4735. foreach($imethods as $parent => $methods)
  4736. {
  4737. $file = $methods['file'];
  4738. $methods = $methods['methods'];
  4739. $par = $this->classes->getClass($parent,$file);
  4740. if ($par) {
  4741. $package = $par->docblock->package;
  4742. }
  4743. usort($methods,array($this,"sortMethod"));
  4744. $result['parent_class'] = $this->getClassLink($parent,$package);
  4745. if (!$result['parent_class']) {
  4746. $result['parent_class'] = $parent . ' (Internal Class)';
  4747. }
  4748. foreach($methods as $method)
  4749. {
  4750. $info = array();
  4751. if ($method->docblock->hasaccess) {
  4752. $info['access'] = $method->docblock->tags['access'][0]->value;
  4753. } else {
  4754. $info['access'] = 'public';
  4755. }
  4756. $info['abstract'] = isset ($method->docblock->tags['abstract'][0]);
  4757. if ($method->isConstructor) $info['constructor'] = 1;
  4758. $returntype = 'void';
  4759. if ($method->isConstructor) {
  4760. $returntype = $method->getClass();
  4761. }
  4762. if ($method->docblock->return) {
  4763. $a = $method->docblock->return->Convert($this);
  4764. $returntype = $method->docblock->return->converted_returnType;
  4765. }
  4766. $info['function_return'] = $returntype;
  4767. $info['static'] = isset ($method->docblock->tags['static'][0]);
  4768. $info['link'] = $method->getLink($this);
  4769. if (!$info['link']) {
  4770. $info['link'] = $method->getFunctionCall();
  4771. }
  4772. $info['name'] = $method->getName();
  4773. if ($method->docblock)
  4774. $info['sdesc'] = $method->docblock->getSDesc($this);
  4775. $params = array();
  4776. if (count($method->docblock->params))
  4777. foreach($method->docblock->params as $param => $val)
  4778. {
  4779. $a = $val->Convert($this);
  4780. $params[$param] = array("var" => $param,"datatype" => $val->converted_returnType,"data" => $a);
  4781. }
  4782. $info['function_call'] = $method->getIntricateFunctionCall($this,$params);
  4783. $result["imethods"][] = $info;
  4784. }
  4785. $results[] = $result;
  4786. $result = array();
  4787. }
  4788. return $results;
  4789. }
  4790. /**
  4791. * Return template-enabled list of inherited class constants
  4792. *
  4793. * uses parserConst helper function getInheritedConsts and generates a
  4794. * template-enabled list using getClassLink()
  4795. * @param parserConst $child class constant
  4796. * @see getClassLink(), parserMethod::getInheritedConsts()
  4797. * @return array Format:
  4798. * <pre>
  4799. * array(
  4800. * array('parent_class' => link to parent class's documentation,
  4801. * 'ivars' =>
  4802. * array(
  4803. * array('name' => inherited constant name,
  4804. * 'link' => link to inherited constant's documentation,
  4805. * 'value' => constant value,
  4806. * 'sdesc' => summary of inherited constant),
  4807. * ...),
  4808. * ...)
  4809. * </pre>
  4810. */
  4811. function getFormattedInheritedConsts($child)
  4812. {
  4813. $package = $child->docblock->package;
  4814. $subpackage = $child->docblock->subpackage;
  4815. $ivars = $child->getInheritedConsts($this);
  4816. $results = array();
  4817. if (!count($ivars)) return $results;
  4818. foreach($ivars as $parent => $vars)
  4819. {
  4820. $file = $vars['file'];
  4821. $vars = $vars['consts'];
  4822. $par = $this->classes->getClass($parent,$file);
  4823. if ($par) {
  4824. $package = $par->docblock->package;
  4825. }
  4826. usort($vars,array($this,"sortVar"));
  4827. $result['parent_class'] = $this->getClassLink($parent,$package);
  4828. if (!$result['parent_class']) {
  4829. $result['parent_class'] = $parent . ' (Internal Class)';
  4830. }
  4831. foreach($vars as $var)
  4832. {
  4833. $info = array();
  4834. if ($var->docblock->hasaccess) {
  4835. $info['access'] = $var->docblock->tags['access'][0]->value;
  4836. } else {
  4837. $info['access'] = 'public';
  4838. }
  4839. $info['name'] = $var->getName();
  4840. $info['link'] = $var->getLink($this);
  4841. if (!$info['link']) {
  4842. $info['link'] = $info['name'] . ' = ' . $var->getValue();
  4843. }
  4844. $info['value'] = $this->postProcess($var->getValue());
  4845. if ($var->docblock)
  4846. $info['sdesc'] = $var->docblock->getSDesc($this);
  4847. $result["iconsts"][] = $info;
  4848. }
  4849. $results[] = $result;
  4850. $result = array();
  4851. }
  4852. return $results;
  4853. }
  4854. /**
  4855. * Return a Smarty template object to operate with
  4856. *
  4857. * This returns a Smarty template with pre-initialized variables for use.
  4858. * If the method "SmartyInit()" exists, it is called.
  4859. * @return Smarty
  4860. */
  4861. function &newSmarty()
  4862. {
  4863. $templ = new Smarty;
  4864. $templ->use_sub_dirs = false;
  4865. $templ->template_dir = realpath($this->smarty_dir . PATH_DELIMITER . 'templates');
  4866. $templatename = get_class($this) . $this->templateName;
  4867. if (!file_exists($this->targetDir . DIRECTORY_SEPARATOR . md5($templatename))) {
  4868. // we'll delete this on finishing conversion
  4869. $this->_compiledDir[$this->targetDir . DIRECTORY_SEPARATOR . md5($templatename)] = 1;
  4870. mkdir($this->targetDir . DIRECTORY_SEPARATOR . md5($templatename),0775);
  4871. }
  4872. $templ->compile_dir = realpath($this->targetDir . PATH_DELIMITER . md5($templatename));
  4873. $templ->config_dir = realpath($this->smarty_dir . PATH_DELIMITER . 'configs');
  4874. $templ->assign("date",date("r",time()));
  4875. $templ->assign("maintitle",$this->title);
  4876. $templ->assign("package",$this->package);
  4877. $templ->assign("phpdocversion",PHPDOCUMENTOR_VER);
  4878. $templ->assign("phpdocwebsite",PHPDOCUMENTOR_WEBSITE);
  4879. $templ->assign("subpackage",$this->subpackage);
  4880. if (method_exists($this,'SmartyInit')) return $this->SmartyInit($templ);
  4881. return $templ;
  4882. }
  4883. /**
  4884. * Finish up parsing/cleanup directories
  4885. */
  4886. function cleanup()
  4887. {
  4888. foreach ($this->_compiledDir as $dir => $one) {
  4889. $this->_rmdir($dir);
  4890. }
  4891. }
  4892. /**
  4893. * Completely remove a directory and its contents
  4894. *
  4895. * @param string $directory
  4896. */
  4897. function _rmdir($directory)
  4898. {
  4899. $handle = @opendir($directory);
  4900. if ($handle) {
  4901. while (false !== ($file = readdir($handle))) {
  4902. if ($file == '.' || $file == '..') {
  4903. continue;
  4904. }
  4905. if (is_dir($directory . DIRECTORY_SEPARATOR . $file)) {
  4906. $this->_rmdir($directory . DIRECTORY_SEPARATOR . $file);
  4907. }
  4908. @unlink($directory . DIRECTORY_SEPARATOR . $file);
  4909. }
  4910. closedir($handle);
  4911. @rmdir($directory);
  4912. }
  4913. }
  4914. /**
  4915. * do all necessary output
  4916. * @see Converter
  4917. * @abstract
  4918. */
  4919. function Output($title)
  4920. {
  4921. phpDocumentor_out("WARNING: Generic Converter::Output was used, no output will be generated");
  4922. }
  4923. /**
  4924. * Set the template directory with a different template base directory
  4925. * @tutorial phpDocumentor.howto.pkg#using.command-line.templatebase
  4926. * @param string template base directory
  4927. * @param string template name
  4928. */
  4929. function setTemplateBase($base, $dir)
  4930. {
  4931. // remove trailing /'s from the base path, if any
  4932. $base = str_replace('\\','/',$base);
  4933. while ($base{strlen($base) - 1} == '/') $base = substr($base,0,strlen($base) - 1);
  4934. $this->templateName = substr($dir,0,strlen($dir) - 1);
  4935. $this->templateDir = $base . "/Converters/" . $this->outputformat . "/" . $this->name . "/templates/" . $dir;
  4936. if (!is_dir($this->templateDir))
  4937. {
  4938. addErrorDie(PDERROR_TEMPLATEDIR_DOESNT_EXIST, $this->templateDir);
  4939. }
  4940. $this->smarty_dir = $this->templateDir;
  4941. if (file_exists($this->templateDir . PATH_DELIMITER . 'options.ini'))
  4942. {
  4943. // retrieve template options, allow array creation
  4944. $this->template_options = phpDocumentor_parse_ini_file($this->templateDir . PATH_DELIMITER . 'options.ini',true);
  4945. }
  4946. }
  4947. /**
  4948. * sets the template directory based on the {@link $outputformat} and {@link $name}
  4949. * Also sets {@link $templateName} to the $dir parameter
  4950. * @param string subdirectory
  4951. */
  4952. function setTemplateDir($dir)
  4953. {
  4954. if ('@DATA-DIR@' != '@'.'DATA-DIR@') {
  4955. $templateBase = str_replace('\\', '/', '@DATA-DIR@/PhpDocumentor/phpDocumentor');
  4956. } else {
  4957. $templateBase = str_replace('\\','/',$GLOBALS['_phpDocumentor_install_dir']) . '/phpDocumentor';
  4958. }
  4959. $this->setTemplateBase($templateBase, $dir);
  4960. }
  4961. /**
  4962. * Get the absolute path to the converter's base directory
  4963. * @return string
  4964. */
  4965. function getConverterDir()
  4966. {
  4967. if ('@DATA-DIR@' != '@' . 'DATA-DIR@') {
  4968. return str_replace('\\', '/', "@DATA-DIR@/PhpDocumentor/phpDocumentor/Converters/") . $this->outputformat . "/" . $this->name;
  4969. } else {
  4970. return str_replace('\\','/',$GLOBALS['_phpDocumentor_install_dir']) ."/phpDocumentor/Converters/" . $this->outputformat . "/" . $this->name;
  4971. }
  4972. }
  4973. /**
  4974. * Parse a global variable's default value for class initialization.
  4975. *
  4976. * If a global variable's default value is "new class" as in:
  4977. * <code>
  4978. * $globalvar = new Parser
  4979. * </code>
  4980. * This method will document it not as "new Parser" but instead as
  4981. * "new {@link Parser}". For examples, see {@link phpdoc.inc}.
  4982. * Many global variables are classes, and phpDocumentor links to their
  4983. * documentation
  4984. * @return string default global variable value with link to class if
  4985. * it's "new Class"
  4986. * @param string default value of a global variable.
  4987. */
  4988. function getGlobalValue($value)
  4989. {
  4990. if (strpos($value,'new') === 0)
  4991. {
  4992. preg_match('/new([^(]*)((?:.|\r|\n)*)/',$value,$newval);
  4993. if (isset($newval[1]))
  4994. {
  4995. $a = Converter::getLink(trim($newval[1]));
  4996. if (!isset($newval[2])) $newval[2] = '';
  4997. if ($a && phpDocumentor_get_class($a) == 'classlink') $value = 'new '.$this->returnSee($a) .
  4998. $this->postProcess($newval[2]);
  4999. }
  5000. return $value;
  5001. }
  5002. return $this->postProcess($value);
  5003. }
  5004. /**
  5005. * Parse an include's file to see if it is a file documented in this project
  5006. *
  5007. * Although not very smart yet, this method will try to look for the
  5008. * included file file.ext:
  5009. *
  5010. * <code>
  5011. * include ("file.ext");
  5012. * </code>
  5013. *
  5014. * If it finds it, it will return a link to the file's documentation. As of
  5015. * 1.2.0rc1, phpDocumentor is smarty enough to find these cases:
  5016. * <ul>
  5017. * <li>absolute path to file</li>
  5018. * <li>./file.ext or ../file.ext</li>
  5019. * <li>relpath/to/file.ext if relpath is a subdirectory of the base parse
  5020. * directory</li>
  5021. * </ul>
  5022. * For examples, see {@link Setup.inc.php} includes.
  5023. * Every include auto-links to the documentation for the file that is included
  5024. * @return string included file with link to docs for file, if found
  5025. * @param string file included by include statement.
  5026. * @param string path of file that has the include statement
  5027. */
  5028. function getIncludeValue($value, $ipath)
  5029. {
  5030. preg_match('/"([^"\']*\.[^"\']*)"/',$value,$match);
  5031. if (!isset($match[1]))
  5032. preg_match('/\'([^"\']*\.[^"\']*)\'/',$value,$match);
  5033. if (isset($match[1]))
  5034. {
  5035. $fancy_per = $this->proceduralpages->pathMatchesParsedFile($match[1],$ipath);
  5036. if ($fancy_per)
  5037. {
  5038. $link = $this->addLink($fancy_per);
  5039. if (is_object($link) && phpDocumentor_get_class($link) == 'pagelink' &&
  5040. isset($this->all_packages[$link->package]))
  5041. {
  5042. $value = $this->returnSee($link,$value);
  5043. }
  5044. } else
  5045. {
  5046. $per = Converter::getLink($match[1]);
  5047. if (is_object($per) && phpDocumentor_get_class($per) == 'pagelink')
  5048. $value = $this->returnSee($per);
  5049. }
  5050. }
  5051. return $value;
  5052. }
  5053. /**
  5054. * Recursively creates all subdirectories that don't exist in the $dir path
  5055. * @param string $dir
  5056. */
  5057. function createParentDir($dir)
  5058. {
  5059. if (empty($dir)) return;
  5060. $tmp = explode(SMART_PATH_DELIMITER,$dir);
  5061. array_pop($tmp);
  5062. $parent = implode(SMART_PATH_DELIMITER,$tmp);
  5063. if ($parent != '' && !file_exists($parent))
  5064. {
  5065. $test = @mkdir($parent,0775);
  5066. if (!$test)
  5067. {
  5068. $this->createParentDir($parent);
  5069. $test = @mkdir($parent,0775);
  5070. phpDocumentor_out("Creating Parent Directory $parent\n");
  5071. } else
  5072. {
  5073. phpDocumentor_out("Creating Parent Directory $parent\n");
  5074. }
  5075. }
  5076. }
  5077. /**
  5078. * Sets the output directory for generated documentation
  5079. *
  5080. * As of 1.3.0RC6, this also sets the compiled templates directory inside
  5081. * the target directory
  5082. * @param string $dir the output directory
  5083. */
  5084. function setTargetDir($dir)
  5085. {
  5086. if (strlen($dir) > 0)
  5087. {
  5088. $this->targetDir = $dir;
  5089. // if directory does exist create it, this should have more error checking in the future
  5090. if (!file_exists($dir))
  5091. {
  5092. $tmp = str_replace(array("/","\\"),SMART_PATH_DELIMITER,$dir);
  5093. if (substr($tmp,-1) == SMART_PATH_DELIMITER)
  5094. {
  5095. $tmp = substr($tmp,0,(strlen($tmp)-1));
  5096. }
  5097. $this->createParentDir($tmp);
  5098. phpDocumentor_out("Creating Directory $dir\n");
  5099. mkdir($dir,0775);
  5100. } elseif (!is_dir($dir))
  5101. {
  5102. echo "Output path: '$dir' is not a directory\n";
  5103. die();
  5104. }
  5105. } else {
  5106. echo "a target directory must be specified\n try phpdoc -h\n";
  5107. die();
  5108. }
  5109. }
  5110. /**
  5111. * Writes a file to target dir
  5112. * @param string
  5113. * @param string
  5114. * @param boolean true if the data is binary and not text
  5115. */
  5116. function writeFile($file,$data,$binary = false)
  5117. {
  5118. if (!file_exists($this->targetDir))
  5119. {
  5120. mkdir($this->targetDir,0775);
  5121. }
  5122. $string = '';
  5123. if ($binary) $string = 'binary file ';
  5124. phpDocumentor_out(" Writing $string".$this->targetDir . PATH_DELIMITER . $file . "\n");
  5125. flush();
  5126. $write = 'w';
  5127. if ($binary) $write = 'wb';
  5128. $fp = fopen($this->targetDir . PATH_DELIMITER . $file,$write);
  5129. set_file_buffer( $fp, 0 );
  5130. fwrite($fp,$data,strlen($data));
  5131. fclose($fp);
  5132. }
  5133. /**
  5134. * Copies a file from the template directory to the target directory
  5135. * thanks to Robert Hoffmann for this fix
  5136. * @param string
  5137. */
  5138. function copyFile($file, $subdir = '')
  5139. {
  5140. if (!file_exists($this->targetDir))
  5141. {
  5142. mkdir($this->targetDir,0775);
  5143. }
  5144. copy($this->templateDir . $subdir . PATH_DELIMITER . $file, $this->targetDir . PATH_DELIMITER . $file);
  5145. }
  5146. /**
  5147. * Return parserStringWithInlineTags::Convert() cache state
  5148. * @see parserStringWithInlineTags::Convert()
  5149. * @abstract
  5150. */
  5151. function getState()
  5152. {
  5153. return true;
  5154. }
  5155. /**
  5156. * Compare parserStringWithInlineTags::Convert() cache state to $state
  5157. * @param mixed
  5158. * @see parserStringWithInlineTags::Convert()
  5159. * @abstract
  5160. */
  5161. function checkState($state)
  5162. {
  5163. return true;
  5164. }
  5165. }
  5166. /**
  5167. * @access private
  5168. * @see Converter::getSortedClassTreeFromClass()
  5169. */
  5170. function rootcmp($a, $b)
  5171. {
  5172. return strnatcasecmp($a['class'],$b['class']);
  5173. }
  5174. /**
  5175. * @access private
  5176. * @global string used to make the first tutorials converted the default package tutorials
  5177. */
  5178. function tutorialcmp($a, $b)
  5179. {
  5180. global $phpDocumentor_DefaultPackageName;
  5181. if ($a == $phpDocumentor_DefaultPackageName) return -1;
  5182. if ($b == $phpDocumentor_DefaultPackageName) return 1;
  5183. return strnatcasecmp($a, $b);
  5184. }
  5185. /**
  5186. * smart htmlentities, doesn't entity the allowed tags list
  5187. * Since version 1.1, this function uses htmlspecialchars instead of
  5188. * htmlentities, for international support
  5189. * This function has been replaced by functionality in {@link ParserDescCleanup.inc}
  5190. * @param string $s
  5191. * @return string browser-displayable page
  5192. * @deprecated As of v1.2, No longer needed, as valid tags are parsed out of the source,
  5193. * and everything else is {@link Converter::postProcess()} handled
  5194. */
  5195. function adv_htmlentities($s)
  5196. {
  5197. return;
  5198. global $phpDocumentor___html,$_phpDocumentor_html_allowed;
  5199. $result = htmlspecialchars($s);
  5200. $entities = array_flip(get_html_translation_table(HTML_SPECIALCHARS));
  5201. $result = strtr($result,$phpDocumentor___html);
  5202. $matches = array();
  5203. preg_match_all('/(&lt;img.*&gt;)/U',$result,$matches);
  5204. for($i=0;$i<count($matches[1]);$i++)
  5205. {
  5206. $result = str_replace($matches[1][$i],strtr($matches[1][$i],array_flip(get_html_translation_table(HTML_SPECIALCHARS))),$result);
  5207. }
  5208. preg_match_all('/(&lt;font.*&gt;)/U',$result,$matches);
  5209. for($i=0;$i<count($matches[1]);$i++)
  5210. {
  5211. $result = str_replace($matches[1][$i],strtr($matches[1][$i],array_flip(get_html_translation_table(HTML_SPECIALCHARS))),$result);
  5212. }
  5213. preg_match_all('/(&lt;ol.*&gt;)/U',$result,$matches);
  5214. for($i=0;$i<count($matches[1]);$i++)
  5215. {
  5216. $result = str_replace($matches[1][$i],strtr($matches[1][$i],array_flip(get_html_translation_table(HTML_SPECIALCHARS))),$result);
  5217. }
  5218. preg_match_all('/(&lt;ul.*&gt;)/U',$result,$matches);
  5219. for($i=0;$i<count($matches[1]);$i++)
  5220. {
  5221. $result = str_replace($matches[1][$i],strtr($matches[1][$i],array_flip(get_html_translation_table(HTML_SPECIALCHARS))),$result);
  5222. }
  5223. preg_match_all('/(&lt;li.*&gt;)/U',$result,$matches);
  5224. for($i=0;$i<count($matches[1]);$i++)
  5225. {
  5226. $result = str_replace($matches[1][$i],strtr($matches[1][$i],array_flip(get_html_translation_table(HTML_SPECIALCHARS))),$result);
  5227. }
  5228. preg_match_all('/(&lt;a .*&gt;)/U',$result,$matches);
  5229. for($i=0;$i<count($matches[1]);$i++)
  5230. {
  5231. $result = str_replace($matches[1][$i],strtr($matches[1][$i],array_flip(get_html_translation_table(HTML_SPECIALCHARS))),$result);
  5232. }
  5233. return $result;
  5234. }
  5235. /**
  5236. * Used solely for setting up the @uses list
  5237. * @package ignore
  5238. * @ignore
  5239. */
  5240. class __dummyConverter extends Converter
  5241. {
  5242. function setTemplateDir(){}
  5243. function setTargetDir(){}
  5244. function getPageName(&$element)
  5245. {
  5246. if (phpDocumentor_get_class($element) == 'parserpage') return '_'.$element->getName();
  5247. return '_'.$element->parent->getName();
  5248. }
  5249. }
  5250. ?>