Complex classes like RwDispatcher often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use RwDispatcher, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 31 | class RwDispatcher extends HttpDispatcherA { |
||
| 32 | /** |
||
| 33 | * @param array $aMaps |
||
| 34 | * @throws ExceptionError |
||
| 35 | * @returns ClassMap |
||
| 36 | */ |
||
| 37 | 20 | static protected function getCurrentMap($aMaps, $sUri = null) { |
|
|
|
|||
| 38 | 20 | if (!is_array($aMaps) || empty($aMaps)) { |
|
| 39 | 1 | return new ErrorProcessorMap(); |
|
| 40 | } |
||
| 41 | |||
| 42 | 19 | if (is_null($sUri)) { |
|
| 43 | 19 | $sUri = vsc::getEnv()->getHttpRequest()->getUri(true); |
|
| 44 | } |
||
| 45 | 19 | $aRegexes = array_keys($aMaps); |
|
| 46 | |||
| 47 | 19 | $aMatches = array(); |
|
| 48 | 19 | foreach ($aRegexes as $sRegex) { |
|
| 49 | 19 | $sFullRegex = '#' . str_replace('#', '\#', $sRegex) . '#iu'; // i for insensitive, u for utf8 |
|
| 50 | try { |
||
| 51 | 19 | $iMatch = preg_match_all($sFullRegex, $sUri, $aMatches, PREG_SET_ORDER); |
|
| 52 | 1 | } catch (ExceptionError $e) { |
|
| 53 | 1 | $f = new ExceptionError( |
|
| 54 | 1 | $e->getMessage() . '<br/> Offending regular expression: <span style="font-weight:normal">' . $sFullRegex . '</span>', |
|
| 55 | 1 | $e->getCode()); |
|
| 56 | 1 | throw $f; |
|
| 57 | } |
||
| 58 | 18 | if ($iMatch) { |
|
| 59 | 18 | $aMatches = array_shift($aMatches); |
|
| 60 | 18 | $aMatches = array_slice($aMatches, 1); |
|
| 61 | |||
| 62 | /* @var MappingA $oMapping */ |
||
| 63 | 18 | $oMapping = $aMaps[$sRegex]; |
|
| 64 | 18 | $oMapping->setTaintedVars($aMatches); |
|
| 65 | 18 | $oMapping->setUrl($sUri); |
|
| 66 | 18 | $oMapping->getModuleMap()->setUrl($sUri); |
|
| 67 | 18 | return $oMapping; |
|
| 68 | } |
||
| 69 | } |
||
| 70 | return null; |
||
| 71 | } |
||
| 72 | |||
| 73 | /** |
||
| 74 | * @returns ModuleMap |
||
| 75 | * @throws ExceptionSitemap |
||
| 76 | */ |
||
| 77 | 2 | public function getCurrentModuleMap() { |
|
| 78 | 2 | $oProcessorMap = $this->getCurrentProcessorMap(); |
|
| 79 | 2 | if (ClassMap::isValid($oProcessorMap)) { |
|
| 80 | 2 | return $this->getCurrentProcessorMap()->getModuleMap(); |
|
| 81 | } else { |
||
| 82 | return $this->getSiteMap()->getCurrentModuleMap(); |
||
| 83 | } |
||
| 84 | } |
||
| 85 | |||
| 86 | /** |
||
| 87 | * @returns ClassMap |
||
| 88 | * @throws ExceptionSitemap |
||
| 89 | * @throws ExceptionError |
||
| 90 | */ |
||
| 91 | 19 | public function getCurrentProcessorMap() { |
|
| 92 | 19 | $oProcessorMap = self::getCurrentMap($this->getSiteMap()->getMaps()); |
|
| 93 | 19 | if (!ClassMap::isValid($oProcessorMap)) { |
|
| 94 | $oProcessorMap = new ErrorProcessorMap(NotFoundProcessor::class); |
||
| 95 | } |
||
| 96 | 19 | return $oProcessorMap; |
|
| 97 | } |
||
| 98 | |||
| 99 | /** |
||
| 100 | * @returns ClassMap |
||
| 101 | * @throws ExceptionError |
||
| 102 | */ |
||
| 103 | 10 | public function getCurrentControllerMap() { |
|
| 104 | 10 | $oProcessorMap = $this->getCurrentProcessorMap(); |
|
| 105 | |||
| 106 | 10 | $oCurrentMap = null; |
|
| 107 | // check if the current processor has some set maps |
||
| 108 | 10 | $aProcessorCtrlMaps = $oProcessorMap->getControllerMaps(); |
|
| 109 | 10 | if (count($aProcessorCtrlMaps) > 0) { |
|
| 110 | $oCurrentMap = self::getCurrentMap($aProcessorCtrlMaps); |
||
| 111 | if (ClassMap::isValid($oCurrentMap) && !ErrorControllerMap::isValid($oCurrentMap)) { |
||
| 112 | return $oCurrentMap; |
||
| 113 | } |
||
| 114 | } |
||
| 115 | |||
| 116 | 10 | $oCurrentModule = $oProcessorMap->getModuleMap(); |
|
| 117 | // merging all controller maps found in the processor map's parent modules |
||
| 118 | do { |
||
| 119 | // check the current module for maps |
||
| 120 | 10 | $aModuleCtrlMaps = $oCurrentModule->getControllerMaps(); |
|
| 121 | 10 | if (count($aModuleCtrlMaps) > 0) { |
|
| 122 | 10 | $oCurrentMap = self::getCurrentMap($aModuleCtrlMaps); |
|
| 123 | } |
||
| 124 | 10 | $oCurrentModule = $oCurrentModule->getModuleMap(); |
|
| 125 | 10 | } while (!ClassMap::isValid($oCurrentMap)); |
|
| 126 | |||
| 127 | 10 | return $oCurrentMap; |
|
| 128 | } |
||
| 129 | |||
| 130 | /** |
||
| 131 | * @throws \vsc\application\sitemaps\ExceptionSitemap |
||
| 132 | * @throws \vsc\presentation\responses\ExceptionResponseError |
||
| 133 | * @returns FrontControllerA |
||
| 134 | */ |
||
| 135 | 1 | public function getFrontController() { |
|
| 136 | 1 | if (!FrontControllerA::isValid($this->oController)) { |
|
| 137 | 1 | $oControllerMapping = $this->getCurrentControllerMap(); |
|
| 138 | |||
| 139 | 1 | if (ClassMap::isValid($oControllerMapping)) { |
|
| 140 | 1 | $sControllerName = $oControllerMapping->getPath(); |
|
| 141 | } |
||
| 142 | |||
| 143 | 1 | if (empty($sControllerName)) { |
|
| 144 | throw new ExceptionResponseError('Could not find the correct front controller', HttpResponseType::NOT_FOUND); |
||
| 145 | } |
||
| 146 | |||
| 147 | /* @var $this->oController FrontControllerA */ |
||
| 148 | 1 | $this->oController = new $sControllerName(); |
|
| 149 | 1 | if (FrontControllerA::isValid($this->oController)) { |
|
| 150 | // adding the map to the controller, allows it to add resources (styles,scripts) from inside it |
||
| 151 | 1 | $this->oController->setMap($oControllerMapping); |
|
| 152 | } |
||
| 153 | } |
||
| 154 | |||
| 155 | 1 | return $this->oController; |
|
| 156 | } |
||
| 157 | |||
| 158 | /** |
||
| 159 | * (non-PHPdoc) |
||
| 160 | * @see vsc/presentation/dispatchers/HttpDispatcherA::getProcessController() |
||
| 161 | * @throws ExceptionSitemap |
||
| 162 | * @throws ExceptionResponseError |
||
| 163 | * @returns ProcessorA |
||
| 164 | */ |
||
| 165 | 3 | public function getProcessController() { |
|
| 166 | 3 | if (!ProcessorA::isValid($this->oProcessor)) { |
|
| 167 | 3 | $oProcessorMap = $this->getCurrentProcessorMap(); |
|
| 168 | 3 | if (!ClassMap::isValid($oProcessorMap)) { |
|
| 169 | // this mainly means nothing was matched to our url, or no mappings exist, so we're falling back to 404 |
||
| 170 | $oProcessorMap = new ErrorProcessorMap(NotFoundProcessor::class, '.*'); |
||
| 171 | $oProcessorMap->setTemplatePath(VSC_SRC_PATH . 'templates'); |
||
| 172 | $oProcessorMap->setTemplate('404.php'); |
||
| 173 | } |
||
| 174 | |||
| 175 | 3 | $sPath = $oProcessorMap->getPath(); |
|
| 176 | try { |
||
| 177 | 3 | if (ClassMap::isValidMap($sPath) || (stristr(basename($sPath), '.') === false && !is_file($sPath))) { |
|
| 178 | |||
| 179 | try { |
||
| 180 | 2 | if (class_exists($sPath)) { |
|
| 181 | 2 | $this->oProcessor = new $sPath(); |
|
| 182 | } else { |
||
| 183 | 2 | $this->oProcessor = new NotFoundProcessor(); |
|
| 184 | } |
||
| 185 | } catch (\Exception $e) { |
||
| 186 | 2 | $this->oProcessor = new ErrorProcessor($e); |
|
| 187 | } |
||
| 188 | 1 | } elseif ($this->getSiteMap()->isValidStaticPath($sPath)) { |
|
| 189 | // static stuff |
||
| 190 | 1 | $this->oProcessor = new StaticFileProcessor(); |
|
| 191 | 1 | $this->oProcessor->setFilePath($sPath); |
|
| 192 | } /*else { |
||
| 193 | $this->oProcessor = new NotFoundProcessor(); |
||
| 194 | }*/ |
||
| 195 | |||
| 196 | 3 | if (ProcessorA::isValid($this->oProcessor)) { |
|
| 197 | 3 | if (!(ErrorProcessor::isValid($this->oProcessor) && MappingA::isValid($this->oProcessor->getMap()))) { |
|
| 198 | // @TODO: this should be a MappingA->merge() when the processor already has a map |
||
| 199 | 2 | $this->oProcessor->setMap($oProcessorMap); |
|
| 200 | } |
||
| 201 | |||
| 202 | // setting the variables defined in the processor into the tainted variables |
||
| 203 | /** @var RwHttpRequest $oRawRequest */ |
||
| 204 | 3 | $oRawRequest = $this->getRequest(); |
|
| 205 | 3 | if (RwHttpRequest::isValid($oRawRequest)) { |
|
| 206 | 3 | $oRawRequest->setTaintedVars($this->oProcessor->getLocalVars()); // FIXME!!! |
|
| 207 | } |
||
| 208 | } else { |
||
| 209 | // broken URL |
||
| 210 | 3 | throw new ExceptionResponseError('Broken URL', 400); |
|
| 211 | } |
||
| 212 | } catch (ExceptionResponseRedirect $e) { |
||
| 213 | // get the response |
||
| 214 | $oResponse = vsc::getEnv()->getHttpResponse(); |
||
| 215 | $oResponse->setLocation($e->getLocation()); |
||
| 216 | ob_end_flush(); |
||
| 217 | $oResponse->outputHeaders(); |
||
| 218 | } |
||
| 219 | } |
||
| 220 | |||
| 221 | 3 | return $this->oProcessor; |
|
| 222 | } |
||
| 223 | |||
| 224 | /** |
||
| 225 | * |
||
| 226 | * @param string $sIncPath |
||
| 227 | * @throws \Exception |
||
| 228 | * @throws ExceptionSitemap |
||
| 229 | * @return boolean |
||
| 230 | */ |
||
| 231 | 19 | public function loadSiteMap($sIncPath) { |
|
| 232 | try { |
||
| 233 | // hic sunt leones |
||
| 234 | /** @var ModuleMap $oMap */ |
||
| 235 | 19 | $oMap = $this->getSiteMap()->map('\A/', $sIncPath); |
|
| 236 | 19 | if (count($oMap->getControllerMaps()) == 0) { |
|
| 237 | 19 | $oMap->map('\A.*\Z', Html5Controller::class); |
|
| 238 | } |
||
| 239 | } catch (ExceptionSitemap $e) { |
||
| 240 | // there was a faulty controller in the sitemap |
||
| 241 | // this will probably result in a incomplete parsed sitemap tree |
||
| 242 | throw ($e); |
||
| 243 | } |
||
| 244 | 19 | return true; |
|
| 245 | } |
||
| 246 | |||
| 247 | public function getView() {} |
||
| 248 | |||
| 249 | 1 | public function getTemplatePath() { |
|
| 250 | 1 | $aMaps = $this->getSiteMap()->getMaps(); |
|
| 251 | 1 | $oProcessorMap = self::getCurrentMap($aMaps); |
|
| 252 | |||
| 253 | 1 | if (ClassMap::isValid($oProcessorMap)) { |
|
| 254 | 1 | $sPath = $oProcessorMap->getTemplatePath(); |
|
| 255 | } else { |
||
| 260 | } |
||
| 261 |