QA_Peardoc_Coverage
[ class tree: QA_Peardoc_Coverage ] [ index: QA_Peardoc_Coverage ] [ all elements ]

Source for file Coverage.php

Documentation is available at Coverage.php

  1. <?php
  2. require_once 'QA/Peardoc/Coverage/ClassList.php';
  3. require_once 'QA/Peardoc/Coverage/MethodList.php';
  4.  
  5. /*
  6. <!-- missing entities -->
  7. <!ENTITY copy "(C)">
  8. <!ENTITY agrave "">
  9. <!ENTITY dollar "$">
  10. <!ENTITY eacute "">
  11. <!ENTITY euro "€">
  12. */
  13.  
  14. /**
  15. * Simple peardoc coverage analysis.
  16. * Compares the classes and methods in PEAR packages
  17. * with the PEAR documentation, trying to find
  18. * out which packages aren't documented at all,
  19. * where documentation of parts is lacking or
  20. * which packages are fully documented.
  21. *
  22. * IDs in peardoc:
  23. * ---------------
  24. * $packagename has "_" replaced with "-"
  25. *
  26. * = Class:
  27. * package.$category.$packagename
  28. *     package.html.html-form
  29. * package.$category.$shortpackagename
  30. *     package.gtk.filedrop
  31. *
  32. * = Methods:
  33. * package.$category.$packagename.$methodname
  34. *     package.html.html-template-it.show
  35. *     package.html.html-template-it.show.desc
  36. *     package.html.html-template-it.show.parameter
  37. *     package.html.html-template-it.show.throws
  38. * package.$category.$packagename.$classname.$methodname
  39. *     package.html.html-quickform.html-quickform.addelement
  40. *
  41. * = Constructor:
  42. * package.$category.$packagename.constructor
  43. *     package.gtk2.entrydialog.constructor
  44. * package.$category.$packagename.$classname.$classname
  45. *     package.datetime.calendar.calendar-day.calendar-day
  46. *
  47. *
  48. @todo:
  49. *  - differentiate between stable and unstable packages
  50. *    (read package.xml)
  51. *
  52. @category QA
  53. @package  QA_Peardoc_Coverage
  54. @author   Christian Weiske <cweiske@php.net>
  55. @license  http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
  56. @version  CVS: $Id: Coverage.php,v 1.11 2007/07/18 18:52:44 cweiske Exp $
  57. @link     http://pear.php.net/package/QA_Peardoc_Coverage
  58. */
  59. {
  60.     /**
  61.     * Special category associations.
  62.     *
  63.     * key: package name
  64.     * value: category name
  65.     */
  66.     public static $arCategoryAssociation = array(
  67.         'benchmark'                 => 'benchmarking',
  68.         'calendar'                  => 'datetime',
  69.         'games_chess'               => 'structures',
  70.         'genealogy_gedcom'          => 'fileformats',
  71.         'fsm'                       => 'processing',
  72.         'i18nv2'                    => 'internationalization',
  73.         'inline_c'                  => 'php',
  74.         'math_numbers'              => 'numbers',
  75.         'message'                   => 'encryption',
  76.         'mime_type'                 => 'tools',
  77.         'ole'                       => 'structures',
  78.         'pager'                     => 'html',
  79.         'pager_sliding'             => 'html',
  80.         'pecl_gen'                  => 'php',
  81.         'phpdoc'                    => 'php',
  82.         'phpdocumentor'             => 'php',
  83.         'safe_html'                 => 'html',
  84.         'search_mnogosearch'        => 'tools',
  85.         'selenium'                  => 'testing',
  86.         'spreadsheet_excel_writer'  => 'fileformats',
  87.         'sql_parser'                => 'database',
  88.         'translation'               => 'internationalization',
  89.         'translation2'              => 'internationalization',
  90.         'tree'                      => 'structures',
  91.         'xml_rpc'                   => 'webservices',
  92.         'xml_rpc2'                  => 'webservices',
  93.     );
  94.  
  95.     /**
  96.     * List with package category name => Doc category name
  97.     * associations.
  98.     *
  99.     * Doc category assignments may be arrays of strings.
  100.     *
  101.     * @var array 
  102.     */
  103.     public static $arCategoryDocNames = array(
  104.         'archive'       => 'fileformats',
  105.         'auth'          => 'authentication',
  106.         'cache'         => 'caching',
  107.         'codegen'       => 'tools',
  108.         'config'        => 'configuration',
  109.         'contact'       => 'fileformats',
  110.         'crypt'         => 'encryption',
  111.         'date'          => 'datetime',
  112.         'db'            => 'database',
  113.         'dba'           => 'database',
  114.         'file'          => array('fileformats''filesystem'),
  115.         'i18n'          => 'internationalization',
  116.         'image'         => 'images',
  117.         'liveuser'      => 'authentication',
  118.         'log'           => 'logging',
  119.         'mdb'           => 'database',
  120.         'mdb2'          => 'database',
  121.         'mp3'           => 'fileformats',
  122.         'net'           => 'networking',
  123.         'rdf'           => 'semanticweb',
  124.         'services'      => 'webservices',
  125.         'soap'          => 'webservices',
  126.         'stream'        => 'streams',
  127.     );
  128.  
  129.     /**
  130.     * Lowercase package names that should be ignored.
  131.     * @var array 
  132.     */
  133.     public static $arIgnoredPackages = array(
  134.         'forum',
  135.         'html_oohform',
  136.         'installphars',
  137.         'perm_liveuser',
  138.         'xml_annotea'
  139.     );
  140.  
  141.  
  142.  
  143.     /**
  144.     * Creates a new coverage checker instance.
  145.     *
  146.     * @param string $strManualPath Full path to the manual.xml file
  147.     *                                of the pear documentation.
  148.     * @param string $strPearDir    Path of PEAR CVS checkout directory
  149.     */
  150.     public function __construct($strManualPath$strPearDir)
  151.     {
  152.         $this->strManualPath $strManualPath;
  153.         $this->strPearDir    $strPearDir;
  154.     }//public function __construct($strManualPath, $strPearDir)
  155.  
  156.  
  157.  
  158.     /**
  159.     * Generates the coverage analysis
  160.     *
  161.     * @return array   Documentation coverage array. Pass it to a render() method.
  162.     */
  163.     public function generateCoverage()
  164.     {
  165.         $this->loadXmlDocument($this->strManualPath);
  166.  
  167.         /*
  168.         *   This is an array with doc statistics.
  169.         *   key:   category
  170.         *   value: array
  171.         *       key:   package name
  172.         *       value: array
  173.         *           special key:   '*docid*'
  174.         *           special value: documentation id
  175.         *                           NULL if no doc
  176.         *           special key:   '*path*'
  177.         *           special value: path to package cvs
  178.         *           key:   classname
  179.         *           value: array, NULL if no doc
  180.         *               key:   methodname
  181.         *               value: ??
  182.         */
  183.         $arDoc = array();
  184.  
  185.         foreach (self::getPackageList($this->strPearDir)
  186.                     as $strPackageDir => $strPackage
  187.         {
  188.             if (in_array(strtolower($strPackage)self::$arIgnoredPackages)) {
  189.                 continue;
  190.             }
  191.  
  192.             $arCategories = self::getCategory($strPackage);
  193.             foreach ($arCategories as $strCategory{
  194.                 $strId $this->getPackageDocId($strPackage$strCategory);
  195.                 if ($strId !== null{
  196.                     break;
  197.                 }
  198.             }
  199.  
  200.             if ($strId === null{
  201.                 $arDoc[$strCategory][$strPackage= array(
  202.                     '*docid*'   => null,
  203.                     '*package*' => $strPackageDir
  204.                 );
  205.             else {
  206.                 $arDoc[$strCategory][$strPackage=
  207.                     $this->getPackageCoverage($strPackage$strCategory$strId$strPackageDir);
  208.             }
  209.         }
  210.  
  211.         ksort($arDoc);
  212.         foreach ($arDoc as &$arPackages{
  213.             ksort($arPackages);
  214.         }
  215.  
  216.         $arDoc['*date*'time();
  217.  
  218.         return $arDoc;
  219.     }//public function generateCoverage()
  220.  
  221.  
  222.  
  223.     /**
  224.     * Renders the coverage analysis into a viewable format.
  225.     *
  226.     * @param array  $arCoverage  Coverage analysis array from generateCoverage()
  227.     * @param string $strRenderer Classname of the renderer
  228.     * @param array  $arOptions   Array of options if needed
  229.     *
  230.     * @return string  Viewable coverage analysis.
  231.     */
  232.     public static function renderCoverage(
  233.         $arCoverage,
  234.         $strRenderer 'QA_Peardoc_Coverage_Renderer_SimplePackageList',
  235.         $arOptions = null
  236.     )
  237.     {
  238.         if (!class_exists($strRenderer)) {
  239.             require_once str_replace('_''/'$strRenderer'.php';
  240.         }
  241.  
  242.         return call_user_func(
  243.             array($strRenderer'render'),
  244.             $arCoverage,
  245.             $arOptions
  246.         );
  247.     }//public static function renderCoverage(..)
  248.  
  249.  
  250.  
  251.     /**
  252.     * Loads the given xml file into a DOM document.
  253.     *
  254.     * @param string $strManualPath Full path to the manual.xml file
  255.     *                                of the pear documentation.
  256.     * @return boolean true if all is ok.
  257.     */
  258.     protected function loadXmlDocument($strManualPath)
  259.     {
  260.         if (!file_exists($strManualPath)) {
  261.             throw new Exception('Manual file does not exist: ' $strManualPath);
  262.         }
  263.         $strPath getcwd();
  264.         chdir(dirname($strManualPath));
  265.  
  266.         $this->doc                     = new DOMDocument();
  267.         $this->doc->resolveExternals   = true;
  268.         $this->doc->substituteEntities = true;
  269.         if ($this->doc->load($strManualPath)) {
  270.             $this->xpath = new DOMXPath($this->doc);
  271.             chdir($strPath);
  272.             return true;
  273.         else {
  274.             chdir($strPath);
  275.             throw new Exception('manual XML could not be loaded.');
  276.         }
  277.     }//protected function loadXmlDocument($strManualPath)
  278.  
  279.  
  280.  
  281.     /**
  282.     * Returns a list of packages and their paths
  283.     *
  284.     * @param string $strPearDir PEAR CVS directory
  285.     * @return array Array with package dir as key and package name as value
  286.     */
  287.     public static function getPackageList($strPearDir)
  288.     {
  289.         $arPackages = array();
  290.  
  291.         if (substr($strPearDir-1!= '/'{
  292.             $strPearDir .= '/';
  293.         }
  294.         foreach (
  295.             glob($strPearDir '*/packag{e,e2}.xml'GLOB_BRACE)
  296.             as $strPackageFilePath
  297.         {
  298.             $strPackageDir substr($strPackageFilePath0strrpos($strPackageFilePath'/'));
  299.  
  300.             $arPackages[$strPackageDirbasename($strPackageDir);
  301.         }
  302.  
  303.         asort($arPackages);
  304.         return $arPackages;
  305.     }//public static function getPackageList($strPearDir)
  306.  
  307.  
  308.  
  309.     /**
  310.     * Returns the category name for the package.
  311.     *
  312.     * @param string $strPackage Package name (e.g. Gtk2_EntryDialog)
  313.     *
  314.     * @return string Array with category names (lowercase)
  315.     */
  316.     public static function getCategory($strPackage)
  317.     {
  318.         $strPackage strtolower($strPackage);
  319.  
  320.         if (isset(self::$arCategoryAssociation[$strPackage])) {
  321.             $strCategory = self::$arCategoryAssociation[$strPackage];
  322.         else {
  323.             $nPos = strpos($strPackage'_');
  324.             if ($nPos === false{
  325.                 $strCategory $strPackage;
  326.             else {
  327.                 $strCategory substr($strPackage0$nPos);
  328.             }
  329.         }
  330.  
  331.         if (isset(self::$arCategoryDocNames[$strCategory])) {
  332.             $arCategories = self::$arCategoryDocNames[$strCategory];
  333.         else {
  334.             $arCategories = array($strCategory);
  335.         }
  336.         if (!is_array($arCategories)) {
  337.             $arCategories = array($arCategories);
  338.         }
  339.         $arCategories array_map('strtolower'$arCategories);
  340.  
  341.         return $arCategories;
  342.     }//public static function getCategory($strPackage)
  343.  
  344.  
  345.  
  346.     /**
  347.     * Returns the ID of the XML node of the package
  348.     * in the pear documentation.
  349.     *
  350.     * @param string $strPackage  Package name
  351.     * @param string $strCategory Category name, gotten from self::getCategory()
  352.     *
  353.     * @return string The id, or NULL if not found -> not documented.
  354.     */
  355.     public function getPackageDocId($strPackage$strCategory)
  356.     {
  357.         $strCategory strtolower($strCategory);
  358.         //gtk2-entrydialog
  359.         $strPackageIdName strtolower(str_replace('_''-'$strPackage));
  360.         //entrydialog
  361.         $strPackageIdName2 strtolower(str_replace('_''-',
  362.                                     substr(
  363.                                         $strPackage,
  364.                                         strpos($strPackage'_'+ 1
  365.                                     )
  366.                              ));
  367.  
  368.         $strId  'package.' $strCategory '.' $strPackageIdName;
  369.         $strId2 'package.' $strCategory '.' $strPackageIdName2;
  370.         $strId3 'core.'    $strCategory '.' $strPackageIdName;
  371.         //echo $strId . "|" . $strId2 . "|" . $strId3 . "\n";
  372.  
  373.         if ($this->existsId($strId)) {
  374.             return $strId;
  375.         else if ($this->existsId($strId2)) {
  376.             return $strId2;
  377.         else if ($this->existsId($strId3)) {
  378.             return $strId3;
  379.         else {
  380.             return null;
  381.         }
  382.     }//public function getPackageDocId($strPackage)
  383.  
  384.  
  385.  
  386.     /**
  387.     * Checks if an id exists in the manual
  388.     *
  389.     * @param string $strId XML id="" to check
  390.     *
  391.     * @return boolean True if it exists, false if not
  392.     */
  393.     public function existsId($strId)
  394.     {
  395.         //echo $strId;
  396.         return $this->doc->getElementById($strId!= null;
  397.     }//public function existsId($strId)
  398.  
  399.  
  400.  
  401.     /**
  402.     * Creates the documentation coverage for the given package.
  403.     *
  404.     * A class is considered documented if either an ID
  405.     * /baseid + "." + classname/ exists, or the classname
  406.     * is surrounded by <classname> tags at least once.
  407.     *
  408.     * Functions/methds are considered as documented if
  409.     * they are mentioned inside a <function> tag or
  410.     * an id like /baseid + "." + classname + "." + functionname/
  411.     * exists.
  412.     *
  413.     * @param string $strPackage    Package name
  414.     * @param string $strCategory   Category (lowercase)
  415.     * @param string $strBaseId     Base documentation id attribute
  416.     * @param string $strPackageDir Package directory
  417.     *
  418.     * @return array Array with doc coverage information
  419.     */
  420.     public function getPackageCoverage($strPackage$strCategory$strBaseId$strPackageDir)
  421.     {
  422.         $arDoc = array(
  423.             '*docid*'   => $strBaseId,
  424.             '*package*' => $strPackageDir
  425.         );
  426.  
  427.         $baseElement $this->doc->getElementById($strBaseId);
  428.         //find <classname> elements
  429.         $arDocClasses = array();
  430.         foreach ($baseElement->getElementsByTagName('classname'as $classElement{
  431.             $arDocClasses[$classElement->nodeValue= true;
  432.         }
  433.  
  434.         $arClasses = array();
  435.         foreach (
  436.             QA_Peardoc_Coverage_ClassList::getFileList($strPackageDir)
  437.             as $strClassFile
  438.         {
  439.             $arClasses array_merge(
  440.                 $arClasses,
  441.                 QA_Peardoc_Coverage_MethodList::getMethods($strClassFile)
  442.             );
  443.         }//foreach file
  444.  
  445.         ksort($arClasses);
  446.  
  447.         foreach ($arClasses as $strClassName => $arMethods{
  448.             if ($strClassName[0== '*'{
  449.                 continue;
  450.             }
  451.             //Check if class is documented
  452.             $strClassDocId $strBaseId '.' strtolower(str_replace('_''-'$strClassName));
  453.             if ($strClassName == $strPackage{
  454.                 $strClassDocId2 $strBaseId;
  455.             else {
  456.                 $strClassDocId2 = null;
  457.             }
  458.  
  459.             if (!isset($arDocClasses[$strClassName]&& !$this->existsId($strClassDocId)) {
  460.                 //class is not documented
  461.                 $arDoc[$strClassName= null;
  462.                 continue;
  463.             }
  464.  
  465.             $arDocMethods = array();
  466.             foreach ($baseElement->getElementsByTagName('function'as $funcElement{
  467.                 $arDocMethods[$funcElement->nodeValue= true;
  468.             }
  469.  
  470.             $arDoc[$strClassName= array();
  471.  
  472.             //check if methods exist
  473.             foreach ($arMethods as $strMethod => $bDocBlock{
  474.                 //omit constructors
  475.                 if ($strMethod == $strClassName || $strMethod == '__construct'{
  476.                     continue;
  477.                 }
  478.  
  479.                 if (isset($arDocMethods[$strMethod])) {
  480.                     //first check if the method is in a <function> tag
  481.                     $arDoc[$strClassName][$strMethod= true;
  482.                 else {
  483.                     //then check if the method has its own section
  484.                     $strMethodDocId $strClassDocId '.' strtolower(str_replace('_''-'$strMethod));
  485.  
  486.                     if (!$this->existsId($strMethodDocId)) {
  487.                         $strMethodDocId2 $strClassDocId2 '.' strtolower(str_replace('_''-'$strMethod));
  488.                         if ($strClassDocId2 !== null && $this->existsId($strMethodDocId2)) {
  489.                             $arDoc[$strClassName][$strMethod= true;
  490.                         else {
  491.                             $arDoc[$strClassName][$strMethod= false;
  492.                         }
  493.                     else {
  494.                         $arDoc[$strClassName][$strMethod= true;
  495.                     }
  496.                 }
  497.             }//foreach method
  498.         }//foreach class
  499.  
  500.         return $arDoc;
  501.     }//public function getPackageCoverage($strPackage, $strCategory, $strBaseId, $strPackageDir)
  502.  
  503. }//class QA_Peardoc_Coverage
  504. ?>

Documentation generated on Mon, 11 Mar 2019 15:10:40 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.