1<?php 2 3namespace dokuwiki\plugin\xref; 4 5/** 6 * Figure out what to send to Grok to hopefully show the right, single hit 7 */ 8class Heuristics 9{ 10 11 /** @var string the definition to search */ 12 protected $def = ''; 13 /** @var string the path to use */ 14 protected $path = ''; 15 /** @var array deprecated classes and their replacements */ 16 protected $deprecations; 17 18 /** 19 * Try to gues what the given reference means and how to best search for it 20 * 21 * @param string $reference 22 */ 23 public function __construct($reference) 24 { 25 $this->loadDeprecations(); 26 27 if ($reference !== '') $reference = $this->checkDeprecation($reference); 28 if ($reference !== '') $reference = $this->checkHash($reference); 29 if ($reference !== '') $reference = $this->checkFilename($reference); 30 if ($reference !== '') $reference = $this->checkNamespace($reference); 31 if ($reference !== '') $reference = $this->checkClassPrefix($reference); 32 if ($reference !== '') $reference = $this->checkVariable($reference); 33 if ($reference !== '') $reference = $this->checkFunction($reference); 34 if ($reference !== '') $reference = $this->checkPSRClass($reference); 35 if ($reference !== '') $this->def = $reference; 36 } 37 38 /** 39 * @return string 40 */ 41 public function getDef() 42 { 43 return trim(preg_replace('/[^\w]+/', '', $this->def)); 44 } 45 46 /** 47 * @return string 48 */ 49 public function getPath() 50 { 51 return trim(preg_replace('/[^\w.]+/', ' ', $this->path)); 52 } 53 54 /** 55 * @return array 56 */ 57 public function getDeprecations() 58 { 59 return $this->deprecations; 60 } 61 62 /** 63 * Replace deprecated classes 64 * 65 * @param string $reference 66 * @return string 67 */ 68 protected function checkDeprecation($reference) 69 { 70 if (isset($this->deprecations[$reference])) { 71 return $this->deprecations[$reference]; 72 } 73 return $reference; 74 } 75 76 /** 77 * Handle things in the form path#symbol 78 * 79 * @param string $reference 80 * @return string 81 */ 82 protected function checkHash($reference) 83 { 84 if (strpos($reference, '#') === false) return $reference; 85 list($this->path, $this->def) = explode('#', $reference, 2); 86 return ''; 87 } 88 89 /** 90 * Known file extension? 91 * 92 * @param string $reference 93 * @return mixed|string 94 */ 95 protected function checkFilename($reference) 96 { 97 if (preg_match('/\.(php|js|css|html)$/', $reference)) { 98 $this->def = ''; 99 $this->path = $reference; 100 return ''; 101 } 102 return $reference; 103 } 104 105 /** 106 * Namespaces are paths 107 * 108 * @param string $reference 109 * @return string 110 */ 111 protected function checkNamespace($reference) 112 { 113 if (strpos($reference, '\\') === false) return $reference; 114 115 $parts = explode('\\', $reference); 116 $parts = array_values(array_filter($parts)); 117 $reference = array_pop($parts); // last part may be more than a class 118 119 // our classes are in inc 120 if ($parts[0] == 'dokuwiki') $parts[0] = 'inc'; 121 122 $this->path = join(' ', $parts); 123 124 return $reference; 125 } 126 127 /** 128 * Is there something called on a class? 129 */ 130 protected function checkClassPrefix($reference) 131 { 132 if ( 133 strpos($reference, '::') === false && 134 strpos($reference, '->') === false 135 ) { 136 return $reference; 137 } 138 list($class, $reference) = preg_split('/(::|->)/', $reference, 2); 139 140 $this->path .= ' ' . $class; 141 $this->def = $reference; 142 return ''; 143 } 144 145 /** 146 * Clearly a variable 147 * 148 * @param string $reference 149 * @return string 150 */ 151 protected function checkVariable($reference) 152 { 153 if ($reference[0] == '$') { 154 $this->def = $reference; 155 return ''; 156 } 157 return $reference; 158 } 159 160 /** 161 * It's a function 162 * 163 * @param string $reference 164 * @return string 165 */ 166 protected function checkFunction($reference) 167 { 168 if (substr($reference, -2) == '()') { 169 $this->def = $reference; 170 return ''; 171 } 172 if (preg_match('/\(.+?\)$/', $reference)) { 173 [$reference, /* $arguments */] = explode('(', $reference, 2); 174 $this->def = $reference; 175 return ''; 176 } 177 return $reference; 178 } 179 180 /** 181 * Upercase followed by lowercase letter, must be a class 182 * 183 * Those are in their own files, so add it to the path 184 * @param $reference 185 * @return mixed|string 186 */ 187 protected function checkPSRClass($reference) 188 { 189 if (preg_match('/^[A-Z][a-z]/', $reference)) { 190 $this->def = $reference; 191 $this->path .= ' ' . $reference; 192 return ''; 193 } 194 return $reference; 195 } 196 197 /** 198 * Load deprecated classes info 199 */ 200 protected function loadDeprecations() 201 { 202 $this->deprecations = []; 203 204 // class aliases 205 $legacy = file_get_contents(DOKU_INC . 'inc/legacy.php'); 206 if (preg_match_all('/class_alias\(\'([^\']+)\', *\'([^\']+)\'\)/', $legacy, $matches, PREG_SET_ORDER)) { 207 foreach ($matches as $match) { 208 $this->deprecations[$match[2]] = $match[1]; 209 } 210 } 211 212 // deprecated classes 213 $deprecations = file_get_contents(DOKU_INC . 'inc/deprecated.php'); 214 if (preg_match_all('/class (.+?) extends (\\\\dokuwiki\\\\.+?)(\s|$|{)/', $deprecations, $matches, PREG_SET_ORDER)) { 215 foreach ($matches as $match) { 216 $this->deprecations[$match[1]] = $match[2]; 217 } 218 } 219 } 220 221} 222