Current File : //opt/RZphp72/includes/QA/Peardoc/Coverage.php |
<?php
require_once 'QA/Peardoc/Coverage/ClassList.php';
require_once 'QA/Peardoc/Coverage/MethodList.php';
/*
<!-- missing entities -->
<!ENTITY copy "(C)">
<!ENTITY agrave "">
<!ENTITY dollar "$">
<!ENTITY eacute "">
<!ENTITY euro "€">
*/
/**
* Simple peardoc coverage analysis.
* Compares the classes and methods in PEAR packages
* with the PEAR documentation, trying to find
* out which packages aren't documented at all,
* where documentation of parts is lacking or
* which packages are fully documented.
*
* IDs in peardoc:
* ---------------
* $packagename has "_" replaced with "-"
*
* = Class:
* package.$category.$packagename
* package.html.html-form
* package.$category.$shortpackagename
* package.gtk.filedrop
*
* = Methods:
* package.$category.$packagename.$methodname
* package.html.html-template-it.show
* package.html.html-template-it.show.desc
* package.html.html-template-it.show.parameter
* package.html.html-template-it.show.throws
* package.$category.$packagename.$classname.$methodname
* package.html.html-quickform.html-quickform.addelement
*
* = Constructor:
* package.$category.$packagename.constructor
* package.gtk2.entrydialog.constructor
* package.$category.$packagename.$classname.$classname
* package.datetime.calendar.calendar-day.calendar-day
*
*
* @todo:
* - differentiate between stable and unstable packages
* (read package.xml)
*
* @category QA
* @package QA_Peardoc_Coverage
* @author Christian Weiske <cweiske@php.net>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version CVS: $Id: Coverage.php,v 1.11 2007/07/18 18:52:44 cweiske Exp $
* @link http://pear.php.net/package/QA_Peardoc_Coverage
*/
class QA_Peardoc_Coverage
{
/**
* Special category associations.
*
* key: package name
* value: category name
*/
public static $arCategoryAssociation = array(
'benchmark' => 'benchmarking',
'calendar' => 'datetime',
'games_chess' => 'structures',
'genealogy_gedcom' => 'fileformats',
'fsm' => 'processing',
'i18nv2' => 'internationalization',
'inline_c' => 'php',
'math_numbers' => 'numbers',
'message' => 'encryption',
'mime_type' => 'tools',
'ole' => 'structures',
'pager' => 'html',
'pager_sliding' => 'html',
'pecl_gen' => 'php',
'phpdoc' => 'php',
'phpdocumentor' => 'php',
'safe_html' => 'html',
'search_mnogosearch' => 'tools',
'selenium' => 'testing',
'spreadsheet_excel_writer' => 'fileformats',
'sql_parser' => 'database',
'translation' => 'internationalization',
'translation2' => 'internationalization',
'tree' => 'structures',
'xml_rpc' => 'webservices',
'xml_rpc2' => 'webservices',
);
/**
* List with package category name => Doc category name
* associations.
*
* Doc category assignments may be arrays of strings.
*
* @var array
*/
public static $arCategoryDocNames = array(
'archive' => 'fileformats',
'auth' => 'authentication',
'cache' => 'caching',
'codegen' => 'tools',
'config' => 'configuration',
'contact' => 'fileformats',
'crypt' => 'encryption',
'date' => 'datetime',
'db' => 'database',
'dba' => 'database',
'file' => array('fileformats', 'filesystem'),
'i18n' => 'internationalization',
'image' => 'images',
'liveuser' => 'authentication',
'log' => 'logging',
'mdb' => 'database',
'mdb2' => 'database',
'mp3' => 'fileformats',
'net' => 'networking',
'rdf' => 'semanticweb',
'services' => 'webservices',
'soap' => 'webservices',
'stream' => 'streams',
);
/**
* Lowercase package names that should be ignored.
* @var array
*/
public static $arIgnoredPackages = array(
'forum',
'html_oohform',
'installphars',
'perm_liveuser',
'xml_annotea'
);
/**
* Creates a new coverage checker instance.
*
* @param string $strManualPath Full path to the manual.xml file
* of the pear documentation.
* @param string $strPearDir Path of PEAR CVS checkout directory
*/
public function __construct($strManualPath, $strPearDir)
{
$this->strManualPath = $strManualPath;
$this->strPearDir = $strPearDir;
}//public function __construct($strManualPath, $strPearDir)
/**
* Generates the coverage analysis
*
* @return array Documentation coverage array. Pass it to a render() method.
*/
public function generateCoverage()
{
$this->loadXmlDocument($this->strManualPath);
/*
* This is an array with doc statistics.
* key: category
* value: array
* key: package name
* value: array
* special key: '*docid*'
* special value: documentation id
* NULL if no doc
* special key: '*path*'
* special value: path to package cvs
* key: classname
* value: array, NULL if no doc
* key: methodname
* value: ??
*/
$arDoc = array();
foreach (self::getPackageList($this->strPearDir)
as $strPackageDir => $strPackage
) {
if (in_array(strtolower($strPackage), self::$arIgnoredPackages)) {
continue;
}
$arCategories = self::getCategory($strPackage);
foreach ($arCategories as $strCategory) {
$strId = $this->getPackageDocId($strPackage, $strCategory);
if ($strId !== null) {
break;
}
}
if ($strId === null) {
$arDoc[$strCategory][$strPackage] = array(
'*docid*' => null,
'*package*' => $strPackageDir
);
} else {
$arDoc[$strCategory][$strPackage] =
$this->getPackageCoverage($strPackage, $strCategory, $strId, $strPackageDir);
}
}
ksort($arDoc);
foreach ($arDoc as &$arPackages) {
ksort($arPackages);
}
$arDoc['*date*'] = time();
return $arDoc;
}//public function generateCoverage()
/**
* Renders the coverage analysis into a viewable format.
*
* @param array $arCoverage Coverage analysis array from generateCoverage()
* @param string $strRenderer Classname of the renderer
* @param array $arOptions Array of options if needed
*
* @return string Viewable coverage analysis.
*/
public static function renderCoverage(
$arCoverage,
$strRenderer = 'QA_Peardoc_Coverage_Renderer_SimplePackageList',
$arOptions = null
)
{
if (!class_exists($strRenderer)) {
require_once str_replace('_', '/', $strRenderer) . '.php';
}
return call_user_func(
array($strRenderer, 'render'),
$arCoverage,
$arOptions
);
}//public static function renderCoverage(..)
/**
* Loads the given xml file into a DOM document.
*
* @param string $strManualPath Full path to the manual.xml file
* of the pear documentation.
* @return boolean true if all is ok.
*/
protected function loadXmlDocument($strManualPath)
{
if (!file_exists($strManualPath)) {
throw new Exception('Manual file does not exist: ' . $strManualPath);
}
$strPath = getcwd();
chdir(dirname($strManualPath));
$this->doc = new DOMDocument();
$this->doc->resolveExternals = true;
$this->doc->substituteEntities = true;
if ($this->doc->load($strManualPath)) {
$this->xpath = new DOMXPath($this->doc);
chdir($strPath);
return true;
} else {
chdir($strPath);
throw new Exception('manual XML could not be loaded.');
}
}//protected function loadXmlDocument($strManualPath)
/**
* Returns a list of packages and their paths
*
* @param string $strPearDir PEAR CVS directory
* @return array Array with package dir as key and package name as value
*/
public static function getPackageList($strPearDir)
{
$arPackages = array();
if (substr($strPearDir, -1) != '/') {
$strPearDir .= '/';
}
foreach (
glob($strPearDir . '*/packag{e,e2}.xml', GLOB_BRACE)
as $strPackageFilePath
) {
$strPackageDir = substr($strPackageFilePath, 0, strrpos($strPackageFilePath, '/'));
$arPackages[$strPackageDir] = basename($strPackageDir);
}
asort($arPackages);
return $arPackages;
}//public static function getPackageList($strPearDir)
/**
* Returns the category name for the package.
*
* @param string $strPackage Package name (e.g. Gtk2_EntryDialog)
*
* @return string Array with category names (lowercase)
*/
public static function getCategory($strPackage)
{
$strPackage = strtolower($strPackage);
if (isset(self::$arCategoryAssociation[$strPackage])) {
$strCategory = self::$arCategoryAssociation[$strPackage];
} else {
$nPos = strpos($strPackage, '_');
if ($nPos === false) {
$strCategory = $strPackage;
} else {
$strCategory = substr($strPackage, 0, $nPos);
}
}
if (isset(self::$arCategoryDocNames[$strCategory])) {
$arCategories = self::$arCategoryDocNames[$strCategory];
} else {
$arCategories = array($strCategory);
}
if (!is_array($arCategories)) {
$arCategories = array($arCategories);
}
$arCategories = array_map('strtolower', $arCategories);
return $arCategories;
}//public static function getCategory($strPackage)
/**
* Returns the ID of the XML node of the package
* in the pear documentation.
*
* @param string $strPackage Package name
* @param string $strCategory Category name, gotten from self::getCategory()
*
* @return string The id, or NULL if not found -> not documented.
*/
public function getPackageDocId($strPackage, $strCategory)
{
$strCategory = strtolower($strCategory);
//gtk2-entrydialog
$strPackageIdName = strtolower(str_replace('_', '-', $strPackage));
//entrydialog
$strPackageIdName2 = strtolower(str_replace('_', '-',
substr(
$strPackage,
strpos($strPackage, '_') + 1
)
));
$strId = 'package.' . $strCategory . '.' . $strPackageIdName;
$strId2 = 'package.' . $strCategory . '.' . $strPackageIdName2;
$strId3 = 'core.' . $strCategory . '.' . $strPackageIdName;
//echo $strId . "|" . $strId2 . "|" . $strId3 . "\n";
if ($this->existsId($strId)) {
return $strId;
} else if ($this->existsId($strId2)) {
return $strId2;
} else if ($this->existsId($strId3)) {
return $strId3;
} else {
return null;
}
}//public function getPackageDocId($strPackage)
/**
* Checks if an id exists in the manual
*
* @param string $strId XML id="" to check
*
* @return boolean True if it exists, false if not
*/
public function existsId($strId)
{
//echo $strId;
return $this->doc->getElementById($strId) != null;
}//public function existsId($strId)
/**
* Creates the documentation coverage for the given package.
*
* A class is considered documented if either an ID
* /baseid + "." + classname/ exists, or the classname
* is surrounded by <classname> tags at least once.
*
* Functions/methds are considered as documented if
* they are mentioned inside a <function> tag or
* an id like /baseid + "." + classname + "." + functionname/
* exists.
*
* @param string $strPackage Package name
* @param string $strCategory Category (lowercase)
* @param string $strBaseId Base documentation id attribute
* @param string $strPackageDir Package directory
*
* @return array Array with doc coverage information
*/
public function getPackageCoverage($strPackage, $strCategory, $strBaseId, $strPackageDir)
{
$arDoc = array(
'*docid*' => $strBaseId,
'*package*' => $strPackageDir
);
$baseElement = $this->doc->getElementById($strBaseId);
//find <classname> elements
$arDocClasses = array();
foreach ($baseElement->getElementsByTagName('classname') as $classElement) {
$arDocClasses[$classElement->nodeValue] = true;
}
$arClasses = array();
foreach (
QA_Peardoc_Coverage_ClassList::getFileList($strPackageDir)
as $strClassFile
) {
$arClasses = array_merge(
$arClasses,
QA_Peardoc_Coverage_MethodList::getMethods($strClassFile)
);
}//foreach file
ksort($arClasses);
foreach ($arClasses as $strClassName => $arMethods) {
if ($strClassName[0] == '*') {
continue;
}
//Check if class is documented
$strClassDocId = $strBaseId . '.' . strtolower(str_replace('_', '-', $strClassName));
if ($strClassName == $strPackage) {
$strClassDocId2 = $strBaseId;
} else {
$strClassDocId2 = null;
}
if (!isset($arDocClasses[$strClassName]) && !$this->existsId($strClassDocId)) {
//class is not documented
$arDoc[$strClassName] = null;
continue;
}
$arDocMethods = array();
foreach ($baseElement->getElementsByTagName('function') as $funcElement) {
$arDocMethods[$funcElement->nodeValue] = true;
}
$arDoc[$strClassName] = array();
//check if methods exist
foreach ($arMethods as $strMethod => $bDocBlock) {
//omit constructors
if ($strMethod == $strClassName || $strMethod == '__construct') {
continue;
}
if (isset($arDocMethods[$strMethod])) {
//first check if the method is in a <function> tag
$arDoc[$strClassName][$strMethod] = true;
} else {
//then check if the method has its own section
$strMethodDocId = $strClassDocId . '.' . strtolower(str_replace('_', '-', $strMethod));
if (!$this->existsId($strMethodDocId)) {
$strMethodDocId2 = $strClassDocId2 . '.' . strtolower(str_replace('_', '-', $strMethod));
if ($strClassDocId2 !== null && $this->existsId($strMethodDocId2)) {
$arDoc[$strClassName][$strMethod] = true;
} else {
$arDoc[$strClassName][$strMethod] = false;
}
} else {
$arDoc[$strClassName][$strMethod] = true;
}
}
}//foreach method
}//foreach class
return $arDoc;
}//public function getPackageCoverage($strPackage, $strCategory, $strBaseId, $strPackageDir)
}//class QA_Peardoc_Coverage
?>