1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361:
<?php
namespace MvcCore\Ext\Debug\Tracy;
class RoutingPanel implements \Tracy\IBarPanel {
const VERSION = '4.2.0';
public static $Id = 'routing-panel';
protected static $viewData = NULL;
public function getId() {
return self::$Id;
}
public function getTab() {
ob_start();
$view = self::SetUpViewData();
if ($view) require(__DIR__ . '/assets/Bar/routing.tab.phtml');
return ob_get_clean();
}
public function getPanel() {
ob_start();
$view = self::SetUpViewData();
if ($view) require(__DIR__ . '/assets/Bar/routing.panel.phtml');
return ob_get_clean();
}
public static function SetUpViewData () {
if (static::$viewData) return static::$viewData;
$app = \MvcCore::GetInstance();
$request = $app->GetRequest();
$router = $app->GetRouter();
if (is_null($router)) return (object) array();
$routes = $router->GetRoutes();
$currentRoute = $router->GetCurrentRoute();
$panelTitle = 'no route';
if (!is_null($currentRoute)) {
$ctrlAndAction = $currentRoute->Controller . ':' . $currentRoute->Action;
if ($ctrlAndAction != $currentRoute->Name) {
$panelTitle = $currentRoute->Name . ' (' . $ctrlAndAction . ')';
} else {
$panelTitle = $ctrlAndAction;
}
}
$items = array();
$matched = FALSE;
foreach ($routes as & $route) {
$items[] = static::completeItem($currentRoute, $route, $request);
if ($currentRoute && $route->Name == $currentRoute->Name) $matched = TRUE;
}
if (!$matched) {
if ($currentRoute instanceof \MvcCore\Route) {
$currentRoute->SetPattern('index.php?controller=...&action=...');
} else {
$currentRoute = new \MvcCore\Route(array('name' => ''));
}
$item = static::completeItem($currentRoute, $currentRoute, $request);
$item->matched = 2;
$items[] = $item;
}
static::$viewData = (object) array(
'panelTitle' => $panelTitle,
'items' => $items,
'requestMethod' => htmlSpecialChars($request->Method, ENT_IGNORE, 'UTF-8'),
'requestBaseUrl' => htmlSpecialChars($request->BaseUrl, ENT_IGNORE, 'UTF-8'),
'requestRequestPath'=> htmlSpecialChars($request->RequestPath, ENT_IGNORE, 'UTF-8'),
);
return static::$viewData;
}
protected static function completeItem (\MvcCore\Route & $currentRoute = NULL, \MvcCore\Route & $route = NULL, \MvcCore\Request & $request = NULL) {
$matched = $currentRoute && $currentRoute->Name == $route->Name ? 1 : 0;
$routeClass = htmlSpecialChars(get_class($route), ENT_QUOTES, 'UTF-8');
$router = \MvcCore\Router::GetInstance();
$lang = isset($router->Lang) ? $router->Lang : '';
$defaultLang = isset($router->DefaultLang) ? $router->DefaultLang : '';
$routePattern = static::getRouteLocalizedRecord($route, 'Pattern', $lang, $defaultLang);
$routeReverse = static::getRouteLocalizedRecord($route, 'Reverse', $lang, $defaultLang);
$routePattern = static::completeFormatedPatternOrReverseCharGroups($routePattern, array('(', ')'));
$routeReverse = static::completeFormatedPatternOrReverseCharGroups($routeReverse, array('{', '}'));
$routeCtrlActionName = $route->Controller . ':' . $route->Action;
$routeCtrlActionLink = static::completeCtrlActionLink($route->Controller, $route->Action);
$routeParams = static::completeParams($route, $route->Params, FALSE);
$matchedCtrlActionName = '';
$matchedCtrlActionLink = array();
$matchedParams = array();
if ($matched) {
$reqParams = $request->Params;
$ctrlPascalCase = \MvcCore\Tool::GetPascalCaseFromDashed($reqParams['controller']);
$actionPascalCase = \MvcCore\Tool::GetPascalCaseFromDashed($reqParams['action']);
$ctrlPascalCase = str_replace('/', '\\', $ctrlPascalCase);
$matchedCtrlActionName = $ctrlPascalCase . ':' . $actionPascalCase;
$matchedCtrlActionLink = static::completeCtrlActionLink($ctrlPascalCase, $actionPascalCase);
$matchedParams = static::completeParams($route, $reqParams, TRUE);
}
return (object) array(
'matched' => $matched,
'routeClass' => $routeClass,
'routePattern' => $routePattern,
'routeReverse' => $routeReverse,
'routeCtrlActionName' => $routeCtrlActionName,
'routeCtrlActionLink' => $routeCtrlActionLink,
'routeName' => $route->Name,
'routeCustomName' => $routeCtrlActionName !== $route->Name,
'routeParams' => $routeParams,
'matchedCtrlActionName' => $matchedCtrlActionName,
'matchedCtrlActionLink' => $matchedCtrlActionLink,
'matchedParams' => $matchedParams,
);
}
protected static function completeParams (\MvcCore\Route & $route, $params = array(), $skipCtrlActionRecord = TRUE) {
$result = array();
$router = \MvcCore\Router::GetInstance();
if (isset($router->Lang) && $router->Lang) {
$result['lang'] = $value2 = '<span class="tracy-dump-string">"' . $router->Lang . '"</span><br />';
}
if (is_null($params)) return $result;
foreach ($params as $key1 => $value1) {
if ($skipCtrlActionRecord) if ($key1 == 'controller' || $key1 == 'action') continue;
$key2 = htmlSpecialChars($key1, ENT_IGNORE, 'UTF-8');
if (is_string($value1)) {
$value2 = '<span class="tracy-dump-string">"'
. htmlSpecialChars($value1, ENT_IGNORE, 'UTF-8')
. '"</span><br />';
} else {
$value2 = \Tracy\Dumper::toHtml($value1, array(
\Tracy\Dumper::COLLAPSE => TRUE,
\Tracy\Dumper::LIVE => TRUE
));
}
$result[$key2] = $value2;
}
return $result;
}
protected static function completeFormatedPatternOrReverseCharGroups ($str, $brackets) {
$str = htmlSpecialChars($str, ENT_NOQUOTES, 'UTF-8');
$matches = static::completeMatchingBracketsPositions($str, $brackets[0], $brackets[1]);
if ($matches) {
$pos = 0;
$result = '';
foreach ($matches as $key => & $match) {
list($subStr, $begin, $end) = $match;
$result .= mb_substr($str, $pos, $begin - $pos);
$result .= '<span class="c'.($key % 6).'">';
$result .= $subStr;
$result .= '</span>';
$pos = $end + 1;
}
$result .= mb_substr($str, $pos);
} else {
$result = $str;
}
return $result;
}
protected static function completeMatchingBracketsPositions ($str, $begin, $end) {
$result = array();
preg_match_all('#([\\'.$begin.'\\'.$end.'])#', $str, $matches, PREG_OFFSET_CAPTURE);
if ($matches[0]) {
$matches = $matches[0];
$level = 0;
$groupBegin = -1;
foreach ($matches as $item) {
list($itemChar, $itemPos) = $item;
$backSlashesCnt = 0;
$backSlashPos = $itemPos - 1;
while ($backSlashPos > -1 && true) {
$prevChar = mb_substr($str, $backSlashPos, 1);
if ($prevChar == '\\') {
$backSlashesCnt += 1;
$backSlashPos -= 1;
} else {
break;
}
}
if (
$backSlashesCnt === 0 || (
($backSlashesCnt > 0 && $backSlashesCnt % 2 === 0)
)) {
if ($itemChar == $begin) {
if ($level === 0) {
$groupBegin = $itemPos;
}
$level += 1;
} else {
$level -= 1;
if ($level === 0) {
$result[] = array(
mb_substr($str, $groupBegin, $itemPos - $groupBegin + 1),
$groupBegin,
$itemPos
);
}
}
}
}
}
return $result;
}
protected static function completeCtrlActionLink ($ctrlName = '', $actionName = '') {
$fullControllerClassName = '';
if (substr($ctrlName, 0, 1) == '\\') {
$fullControllerClassName = substr($ctrlName, 1);
} else {
$fullControllerClassName = '\\App\\Controllers\\' . $ctrlName;
}
$result = array('', $fullControllerClassName . ':' . $actionName . 'Action');
try {
$ctrlReflection = new \ReflectionClass($fullControllerClassName);
if ($ctrlReflection instanceof \ReflectionClass) {
$file = $ctrlReflection->getFileName();
$actionReflection = $ctrlReflection->getMethod($actionName . 'Action');
if ($actionReflection instanceof \ReflectionMethod) {
$line = $actionReflection->getStartLine();
$result = array(
\Tracy\Helpers::editorUri($file, $line),
$fullControllerClassName . ':' . $actionName . 'Action'
);
}
}
} catch (\Exception $e) {
}
return $result;
}
protected static function getRouteLocalizedRecord (\MvcCore\Route & $route, $routeRecordKey = '', $lang = '', $defaultLang = '') {
if (gettype($route->$routeRecordKey) == 'array') {
$routeRecordKey = $route->$routeRecordKey;
if (isset($routeRecordKey[$lang])) {
return $routeRecordKey[$lang];
} else if (isset($routeRecordKey[$defaultLang])) {
return $routeRecordKey[$defaultLang];
}
return reset($routeRecordKey);
}
return $route->$routeRecordKey;
}
}