Search2.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <?php
  2. /**
  3. * Class to search the phpgtk2 manual.
  4. *
  5. * Use the static PhpGtkDoc_Search2::find() method
  6. * to search for a string, and use one of the
  7. * PhpGtkDoc_Search2_Result_* classes to display the result.
  8. *
  9. * @author Christian Weiske <cweiske@php.net>
  10. */
  11. class PhpGtkDoc_Search2
  12. {
  13. /**
  14. * Searches for the given string
  15. * This function returns a nested array which allows the search results
  16. * being displayed by sections like enums/methods/classes/...
  17. *
  18. * @param string The string to search. It is automatically split into substrings by the space char
  19. * @param string The index file to use
  20. *
  21. * @return array Nested array with results. Format:
  22. * array( 1 => subarray(), 2 => subarray(), 3 => subarray())
  23. * subarray( 'class' => array_of_files(), 'method' => array_of_files(), ...)
  24. */
  25. public static function find($strSearch, $strIndexFile)
  26. {
  27. if (!file_exists($strIndexFile)) {
  28. throw new Exception('Index file does not exist: ' . $strIndexFile);
  29. }
  30. //TODO: Split better, so that we can exclude something with minus and so
  31. $arSearchWords = explode(' ', strtolower($strSearch));
  32. $arIndex = unserialize(file_get_contents($strIndexFile));
  33. $arResults = array();//all the found files for the indices
  34. $arWordsResults = array();//the found files which were found for each word
  35. foreach ($arSearchWords as $strWord) {
  36. $arWordsResults[$strWord] = array();//needs to be done
  37. if (isset($arIndex[$strWord])) {
  38. $arFound = $arIndex[$strWord];
  39. foreach ($arFound as $nIndex => $arFiles) {
  40. foreach ($arFiles as $strFile) {
  41. $arWordsResults[$strWord][] = $strFile;
  42. $arResults[$nIndex][$strFile] = 1;
  43. }
  44. }
  45. }
  46. }
  47. //remove all the files which were not found for all the words
  48. //firstly, intersect all the single arrays of the words
  49. $arAllWords = array();
  50. $bFirst = true;
  51. foreach ($arWordsResults as $strWord => $arWordResults) {
  52. if ($bFirst) {
  53. $arAllWords = $arWordResults;
  54. $bFirst = false;
  55. } else {
  56. $arAllWords = array_intersect($arAllWords, $arWordResults);
  57. }
  58. }
  59. ksort($arResults);//that key 1 is first
  60. //remove the not-in-all found files from the $arResults array
  61. foreach ($arResults as $nId => $arWords) {
  62. foreach ($arWords as $strWord => $nOne) {
  63. if (!in_array($strWord, $arAllWords)) {
  64. //remove the one file from the found list
  65. unset($arResults[$nId][$strWord]);
  66. } else {
  67. //remove the file from the accept list to ensure every file is
  68. //listed only once (try searching for "window gtk force")
  69. unset($arAllWords[array_search($strWord, $arAllWords)]);
  70. }
  71. }
  72. }
  73. //now split the subarrays 2 and 3 into sections: enums, properties, signals...
  74. foreach ($arResults as $nId => $arFiles) {
  75. $arResults[$nId] = self::splitIntoSections( $arFiles);
  76. }
  77. return self::reorderResult($arResults);
  78. }//public static function find($strSearch, $strIndexFile)
  79. /**
  80. * Re-orders the result to give a better order.
  81. * E.g. methods of the class which have the search string in it
  82. * will be moved to level 3
  83. *
  84. * @param array $arResults Result array
  85. * @return array Fixed result array
  86. */
  87. protected static function reorderResult($arResult)
  88. {
  89. //if a class is found, move the methods of this class to level 3,
  90. //as they all match. So non-same-class methods with the search
  91. //string should have higher priority
  92. if (isset($arResult[1]['class'])) {
  93. foreach ($arResult[1] as $strType => $arLevel) {
  94. if ($strType != 'class') {
  95. $arResult[3][$strType] = $arLevel;
  96. unset($arResult[1][$strType]);
  97. }
  98. }
  99. }
  100. return $arResult;
  101. }//protected static function reorderResult($arResult)
  102. /**
  103. * splits an array with files as keys into sections
  104. * like enums, properties, signals, ...
  105. *
  106. * @param array $arFiles array with file names as keys and a number as value
  107. * @return array array with subarrays, files as values in the subarrays. The keys for the subarrays are the section names
  108. */
  109. protected static function splitIntoSections($arFiles)
  110. {
  111. $arSected = array();
  112. $arRegexs['tutorials'] = '/^tutorials\\./';//has to be before class and method
  113. $arRegexs['class'] = '/^[a-zA-Z0-9]+\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+$/';
  114. $arRegexs['constructor']= '/\\.constructor\\.([a-zA-Z0-9_]+\\.)?/';
  115. $arRegexs['enum'] = '/^[a-zA-Z0-9]+\\.enum\\./';
  116. $arRegexs['method'] = '/^[a-zA-Z0-9]+(\\.[a-zA-Z0-9]+)?\\.method\\./'; //the (..)? is for things like gdk::main()
  117. $arRegexs['property'] = '/^[a-zA-Z0-9]+\\.[a-zA-Z0-9]+\\.(prop|property)\\./';
  118. $arRegexs['field'] = '/^[a-zA-Z0-9]+\\.[a-zA-Z0-9]+\\.(field)\\./';
  119. $arRegexs['signal'] = '/^[a-zA-Z0-9]+\\.[a-zA-Z0-9]+\\.signal\\./';
  120. foreach ($arFiles as $strFile => $nOne) {
  121. $strBaseFile = basename($strFile);
  122. $bFound = false;
  123. foreach ($arRegexs as $strSection => $strRegex) {
  124. if( preg_match( $strRegex, $strBaseFile)) {
  125. $arSected[$strSection][] = $strFile;
  126. $bFound = true;
  127. break;
  128. }
  129. }
  130. if( !$bFound) {
  131. $arSected['unknown'][] = $strFile;
  132. }
  133. }
  134. //sort the sections internally by filename
  135. foreach( $arSected as $strSection => $arFiles) {
  136. sort( $arSected[$strSection]);
  137. }
  138. return $arSected;
  139. }//protected static function splitIntoSections($arFiles)
  140. /**
  141. * Returns the file title for the given file
  142. * for efficient working, the category has to be given
  143. *
  144. * The function tries to get the file title with some algorithms,
  145. * NOT from the direct html files.
  146. *
  147. * @param string $strFilename The file name, e.g. gtk.gtkcolorselection.method.get_color.php
  148. * @param string $strCategory The category of the file, e.g. class/enum/constructor/...
  149. *
  150. * @return string The file title, can be used for link titles
  151. */
  152. public static function getFileTitle($strFilename, $strCategory)
  153. {
  154. $arParts = explode('.', basename($strFilename));
  155. $nParts = count($arParts);
  156. switch ($strCategory) {
  157. case 'class':
  158. if ($arParts[1] == 'functions') {
  159. //function list gtk.functions.php
  160. return self::niceClassName($arParts[0]) . ' functions';
  161. } else {
  162. //normal class name gtk.gtkentry.php
  163. return self::niceClassName($arParts[1]);
  164. }
  165. case 'constructor':
  166. if ($nParts == 5) {//static method constructor
  167. return self::niceClassName($arParts[1]) . '::' . $arParts[3] . '()';
  168. } else {
  169. return self::niceClassName($arParts[1]) . ' constructor';
  170. }
  171. case 'method':
  172. if ($nParts == 5) {//class with method
  173. return self::niceClassName($arParts[1]) . '::' . $arParts[3] . '()';
  174. } else {//gtk/gdk method
  175. return self::niceClassName($arParts[0]) . '::' . $arParts[2] . '()';
  176. }
  177. case 'property':
  178. if ($nParts == 5) {//class property
  179. return self::niceClassName($arParts[1]) . '::' . $arParts[3];
  180. } else {//gtk/gdk property //does this exist?
  181. return self::niceClassName($arParts[0]) . '::' . $arParts[2];
  182. }
  183. case 'field':
  184. if ($nParts == 5) {//class field
  185. return self::niceClassName($arParts[1]) . '::' . $arParts[3];
  186. } else {//gtk/gdk field //does this exist?
  187. return self::niceClassName($arParts[0]) . '::' . $arParts[2];
  188. }
  189. case 'signal':
  190. if ($nParts == 5) {//class signal
  191. return self::niceClassName($arParts[1]) . ': ' . $arParts[3];
  192. } else {//gtk/gdk signal
  193. return self::niceClassName($arParts[0]) . ': ' . $arParts[2];
  194. }
  195. case 'enum':
  196. return self::niceClassName($arParts[0]) . ucfirst($arParts[2]) . ' enum';
  197. case 'tutorials':
  198. if ($nParts == 2) {
  199. return 'Tutorial list';
  200. } else if ($nParts == 3) {
  201. return ucfirst($arParts[1]) . ' tutorial';
  202. } else {
  203. return ucfirst( $arParts[1]) . ' tutorial: ' . $arParts[2];
  204. }
  205. default:
  206. return $strFilename;
  207. }
  208. }//public static function getFileTitle($strFilename, $strCategory)
  209. /**
  210. * Makes a nice class name from a lowercase name
  211. * given "gdkcolor" it returns "GdkColor"
  212. *
  213. * @param string The lowercase class name
  214. * @return string The nice cased class name
  215. */
  216. protected static function niceClassName( $strLowercaseClass)
  217. {
  218. $strPrefix = substr( $strLowercaseClass, 0, 3);
  219. if ($strPrefix == 'gdk' || $strPrefix == 'gtk' || $strPrefix == 'atk') {
  220. $strNice = ucfirst($strPrefix) . ucfirst(substr($strLowercaseClass, 3));
  221. } else if ($strPrefix == 'pan') {
  222. $strNice = ucfirst($strPrefix) . ucfirst(substr($strLowercaseClass, 5));
  223. } else {
  224. $strNice = ucfirst($strLowercaseClass);
  225. }
  226. return $strNice;
  227. }//protected static function niceClassName( $strLowercaseClass)
  228. }//class PhpGtkDoc_Search2
  229. ?>