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: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565:
<?php
/**
* MvcCore
*
* This source file is subject to the BSD 3 License
* For the full copyright and license information, please view
* the LICENSE.md file that are distributed with this source code.
*
* @copyright Copyright (c) 2016 Tom Flidr (https://github.com/mvccore)
* @license https://mvccore.github.io/docs/mvccore/5.0.0/LICENCE.md
*/
namespace MvcCore\Route;
trait UrlBuilding {
/**
* @inheritDocs
* @param array $params
* @param array $defaultParams
* @param string $direction
* @return array Filtered params array.
*/
public function Filter (array & $params = [], array & $defaultParams = [], $direction = \MvcCore\IRoute::CONFIG_FILTER_IN) {
/** @var $this \MvcCore\Route */
if (!$this->filters || !isset($this->filters[$direction]))
return [TRUE, $params];
list($closureCalling, $handler) = $this->filters[$direction];
try {
$req = \MvcCore\Application::GetInstance()->GetRequest();
if ($closureCalling) {
$newParams = $handler($params, $defaultParams, $req);
} else {
$newParams = call_user_func_array($handler, [$params, $defaultParams, $req]);
}
$success = TRUE;
} catch (\RuntimeException $e) {
$debugClass = \MvcCore\Application::GetInstance()->GetDebugClass();
$debugClass::Log($e, \MvcCore\IDebug::ERROR);
$success = FALSE;
$newParams = $params;
}
return [$success, $newParams];
}
/**
* @inheritDocs
* @param \MvcCore\Request $request
* Currently requested request object.
* @param array $params
* URL params from application point completed
* by developer.
* @param array $defaultUrlParams
* Requested URL route params and query string
* params without escaped HTML special chars:
* `< > & " ' &`.
* @param string $queryStringParamsSepatator
* Query params separator, `&` by default. Always
* automatically completed by router instance.
* @param bool $splitUrl
* Boolean value about to split completed result URL
* into two parts or not. Default is FALSE to return
* a string array with only one record - the result
* URL. If `TRUE`, result url is split into two
* parts and function return array with two items.
* @return \string[] Result URL address in array. If last argument is
* `FALSE` by default, this function returns only
* single item array with result URL. If last
* argument is `TRUE`, function returns result URL
* in two parts - domain part with base path and
* path part with query string.
*/
public function Url (\MvcCore\IRequest $request, array & $params = [], array & $defaultUrlParams = [], $queryStringParamsSepatator = '&', $splitUrl = FALSE) {
/** @var $this \MvcCore\Route */
// check reverse initialization
if ($this->reverseParams === NULL) $this->initReverse();
// unset all params with the same values as route defaults configuration
foreach ($params as $paramName => $paramValue)
if (isset($this->defaults[$paramName]) && $this->defaults[$paramName] == $paramValue)
unset($params[$paramName]);
// complete and filter all params to build reverse pattern
if (count($this->reverseParams) === 0) {
$allParamsClone = array_merge([], $params);
} else {// complete params with necessary values to build reverse pattern (and than query string)
$emptyReverseParams = array_fill_keys(array_keys($this->reverseParams), NULL);
$allMergedParams = array_merge($this->defaults, $defaultUrlParams, $params);
// all params clone contains only keys necessary to build reverse
// pattern for this route and all given `$params` keys, nothing more
// from currently requested URL
$allParamsClone = array_merge(
$emptyReverseParams, array_intersect_key($allMergedParams, $emptyReverseParams), $params
);
}
// filter params
list(,$filteredParams) = $this->Filter($allParamsClone, $defaultUrlParams, \MvcCore\IRoute::CONFIG_FILTER_OUT);
$filteredParams = $filteredParams ?: [];
// split params into domain params array and into path and query params array
$domainParams = $this->urlGetAndRemoveDomainPercentageParams($filteredParams);
// build reverse pattern
$result = $this->urlComposeByReverseSectionsAndParams(
$this->reverse,
$this->reverseSections,
$this->reverseParams,
$filteredParams,
$this->defaults
);
// add all remaining params to query string
if ($filteredParams) {
// `http_build_query()` automatically converts all XSS chars to entities (`< > & " ' &`):
$result .= (mb_strpos($result, '?') !== FALSE ? $queryStringParamsSepatator : '?')
. str_replace('%2F', '/', http_build_query($filteredParams, '', $queryStringParamsSepatator, PHP_QUERY_RFC3986));
}
return $this->urlAbsPartAndSplit($request, $result, $domainParams, $splitUrl);
}
/**
* Compose URL by reverse pattern value, by reverse (fixed or variable)
* sections info, by reverse params info (start, end, length), by given
* params array with final values and by default params values defined by
* route object. Unset all applied params from given `$params` array to not
* render them again in possible query string later.
* @param string $reverse A route reverse string without brackets defining
* URL variable sections.
* @param \stdClass[] $reverseSections Reverse sections info, where each item contains
* data about if section is fixed or not, start,
* length and end of section.
* @param array $reverseParams An array with keys as param names and values as
* `\stdClass` objects with data about each reverse param.
* @param array $params An array with keys as param names and values as
* param final values.
* @param array $defaults An array with keys as param names and values as
* param default values defined in route object.
* @return string
*/
protected function urlComposeByReverseSectionsAndParams (& $reverse, & $reverseSections, & $reverseParams, & $params, & $defaults) {
/** @var $this \MvcCore\Route */
$sections = [];
$paramIndex = 0;
$reverseParamsKeys = array_keys($reverseParams);
$paramsCount = count($reverseParamsKeys);
$anyParams = $paramsCount > 0;
foreach ($reverseSections as $sectionIndex => & $section) {
$fixed = $section->fixed;
$sectionResult = '';
if ($anyParams) {
$sectionOffset = $section->start;
$sectionParamsCount = 0;
$defaultValuesCount = 0;
while ($paramIndex < $paramsCount) {
$paramKey = $reverseParamsKeys[$paramIndex];
$reverseParam = $reverseParams[$paramKey];
if ($reverseParam->sectionIndex !== $sectionIndex) break;
$sectionParamsCount++;
$paramStart = $reverseParam->reverseStart;
if ($sectionOffset < $paramStart)
$sectionResult .= mb_substr($reverse, $sectionOffset, $paramStart - $sectionOffset);
$paramName = $reverseParam->name;
$paramValue = $params[$paramName];
$paramValueStr = is_array($paramValue) ? implode(',', $paramValue) : strval($paramValue);
if (
$paramValue === NULL || (
array_key_exists($paramName, $defaults) &&
$paramValueStr == strval($defaults[$paramName])
)
) $defaultValuesCount++;
$sectionResult .= htmlspecialchars($paramValueStr, ENT_QUOTES);
unset($params[$paramName]);
$paramIndex += 1;
$sectionOffset = $reverseParam->reverseEnd;
}
$sectionEnd = $section->end;
if (!$fixed && $sectionParamsCount === $defaultValuesCount) {
$sectionResult = '';
} else if ($sectionOffset < $sectionEnd) {
$sectionResult .= mb_substr($reverse, $sectionOffset, $sectionEnd - $sectionOffset);
}
} else if ($fixed) {
$sectionResult = mb_substr($reverse, $section->start, $section->length);
}
$sections[] = $sectionResult;
}
$result = implode('', $sections);
$result = & $this->urlCorrectTrailingSlashBehaviour($result);
return $result;
}
/**
* After final URL is completed, split result URL into two parts. First part
* as scheme, domain part and base path and second part as application
* request path and query string.
* @param \MvcCore\Request $request
* A request object.
* @param string $resultUrl
* Result URL to split. REsult URL still could
* contain domain part or base path replacements.
* @param array $domainParams
* Array with params for first URL part (scheme,
* domain, base path).
* @param bool $splitUrl
* Boolean value about to split completed result URL
* into two parts or not. Default is FALSE to return
* a string array with only one record - the result
* URL. If `TRUE`, result url is split into two
* parts and function return array with two items.
* @return \string[] Result URL address in array. If last argument is
* `FALSE` by default, this function returns only
* single item array with result URL. If last
* argument is `TRUE`, function returns result URL
* in two parts - domain part with base path and
* path part with query string.
*/
protected function urlAbsPartAndSplit (\MvcCore\IRequest $request, $resultUrl, & $domainParams, $splitUrl) {
/** @var $this \MvcCore\Route */
$domainParamsFlag = $this->flags[1];
$basePathInReverse = FALSE;
if ($domainParamsFlag >= static::FLAG_HOST_BASEPATH) {
$basePathInReverse = TRUE;
$domainParamsFlag -= static::FLAG_HOST_BASEPATH;
}
if ($this->flags[0]) {
// route is defined as absolute with possible `%domain%` and other params
// process possible replacements in reverse result - `%host%`, `%domain%`, `%tld%` and `%sld%`
$this->urlReplaceDomainReverseParams($request, $resultUrl, $domainParams, $domainParamsFlag);
// try to find URL position after domain part and after base path part
if ($basePathInReverse) {
return $this->urlAbsPartAndSplitByReverseBasePath($request, $resultUrl, $domainParams, $splitUrl);
} else {
return $this->urlAbsPartAndSplitByRequestedBasePath($request, $resultUrl, $splitUrl);
}
} else {
// route is not defined as absolute, there could be only flag
// in domain params array to complete absolute URL by developer
// and there could be also `basePath` param defined.
return $this->urlAbsPartAndSplitByGlobalSwitchOrBasePath(
$request, $resultUrl, $domainParams, (bool) $domainParamsFlag, $splitUrl
);
}
}
/**
* Replace all domain params percentage replacements in finally completed
* URL by given `$domainParams` array values. If there is founded any
* percentage replacement which is not presented in `$domainParams` array,
* there is used value from request object.
* @param \MvcCore\Request $request A request object.
* @param string $resultUrl Result URL to split. REsult URL
* still could contain domain part
* or base path replacements.
* @param array $domainParams Array with params for first URL
* part (scheme, domain, base path).
* @param mixed $domainParamsFlag Second route flag about domain
* without value about base path.
* This value contains info what
* percentage replacements was
* contained in reverse pattern.
*/
protected function urlReplaceDomainReverseParams (\MvcCore\IRequest $request, & $resultUrl, & $domainParams, $domainParamsFlag) {
/** @var $this \MvcCore\Route */
$replacements = [];
$values = [];
$router = $this->router;
if ($domainParamsFlag == static::FLAG_HOST_HOST) {
$hostParamName = $router::URL_PARAM_HOST;
$replacements[] = static::PLACEHOLDER_HOST;
$values[] = isset($domainParams[$hostParamName])
? $domainParams[$hostParamName]
: $request->GetHost();
} else if ($domainParamsFlag == static::FLAG_HOST_DOMAIN) {
$domainParamName = $router::URL_PARAM_DOMAIN;
$replacements[] = static::PLACEHOLDER_DOMAIN;
$values[] = isset($domainParams[$domainParamName])
? $domainParams[$domainParamName]
: $request->GetSecondLevelDomain() . '.' . $request->GetTopLevelDomain();
} else {
if ($domainParamsFlag == static::FLAG_HOST_TLD) {
$tldParamName = $router::URL_PARAM_TLD;
$replacements[] = static::PLACEHOLDER_TLD;
$values[] = isset($domainParams[$tldParamName])
? $domainParams[$tldParamName]
: $request->GetTopLevelDomain();
} else if ($domainParamsFlag == static::FLAG_HOST_SLD) {
$sldParamName = $router::URL_PARAM_SLD;
$replacements[] = static::PLACEHOLDER_SLD;
$values[] = isset($domainParams[$sldParamName])
? $domainParams[$sldParamName]
: $request->GetSecondLevelDomain();
} else if ($domainParamsFlag == static::FLAG_HOST_TLD + static::FLAG_HOST_SLD) {
$tldParamName = $router::URL_PARAM_TLD;
$sldParamName = $router::URL_PARAM_SLD;
$replacements[] = static::PLACEHOLDER_TLD;
$replacements[] = static::PLACEHOLDER_SLD;
$values[] = isset($domainParams[$tldParamName])
? $domainParams[$tldParamName]
: $request->GetTopLevelDomain();
$values[] = isset($domainParams[$sldParamName])
? $domainParams[$sldParamName]
: $request->GetSecondLevelDomain();
}
}
$resultUrl = str_replace($replacements, $values, $resultUrl);
}
/**
* After final URL is completed, split result URL into two parts if there
* is contained domain part and base path in reverse, what is base material
* to complete result URL. If there is found base path percentage
* replacement in result url, split url after that percentage replacement
* and replace that part with domain param value or request base path value.
* @param \MvcCore\Request $request
* A request object.
* @param string $resultUrl
* Result URL to split. Result URL still could
* contain domain part or base path replacements.
* @param array $domainParams
* Array with params for first URL part (scheme,
* domain, base path).
* @param bool $splitUrl
* Boolean value about to split completed result URL
* into two parts or not. Default is FALSE to return
* a string array with only one record - the result
* URL. If `TRUE`, result url is split into two
* parts and function return array with two items.
* @return \string[] Result URL address in array. If last argument is
* `FALSE` by default, this function returns only
* single item array with result URL. If last
* argument is `TRUE`, function returns result URL
* in two parts - domain part with base path and
* path part with query string.
*/
protected function urlAbsPartAndSplitByReverseBasePath (\MvcCore\IRequest $request, $resultUrl, & $domainParams, $splitUrl) {
/** @var $this \MvcCore\Route */
$doubleSlashPos = mb_strpos($resultUrl, '//');
$doubleSlashPos = $doubleSlashPos === FALSE
? 0
: $doubleSlashPos + 2;
$router = $this->router;
$basePathPlaceHolderPos = mb_strpos($resultUrl, static::PLACEHOLDER_BASEPATH, $doubleSlashPos);
if ($basePathPlaceHolderPos === FALSE) {
return $this->urlAbsPartAndSplitByRequestedBasePath(
$request, $resultUrl, $splitUrl
);
}
$pathPart = mb_substr($resultUrl, $basePathPlaceHolderPos + mb_strlen(static::PLACEHOLDER_BASEPATH));
$questionMarkPos = mb_strpos($pathPart, '?');
if ($questionMarkPos === FALSE) {
$pathPart = str_replace('//', '/', $pathPart);
} else {
$pathPart = str_replace('//', '/', mb_substr($pathPart, 0, $questionMarkPos))
. mb_substr($pathPart, $questionMarkPos);
}
$basePart = mb_substr($resultUrl, 0, $basePathPlaceHolderPos);
$basePathParamName = $router::URL_PARAM_BASEPATH;
$basePart .= isset($domainParams[$basePathParamName])
? $domainParams[$basePathParamName]
: $request->GetBasePath();
if ($this->flags[0] === static::FLAG_SCHEME_ANY)
$basePart = $request->GetScheme() . $basePart;
if ($splitUrl) return [$basePart, $pathPart];
return [$basePart . $pathPart];
}
/**
* After final URL is completed, split result URL into two parts if there
* is contained domain part and base path in reverse, what is base material
* to complete result URL. Try to found the point in result URL, where is
* base path end and application request path begin. By that point split and
* return result URL.
* @param \MvcCore\Request $request
* A request object.
* @param string $resultUrl
* Result URL to split. Result URL still could
* contain domain part or base path replacements.
* @param bool $splitUrl
* Boolean value about to split completed result URL
* into two parts or not. Default is FALSE to return
* a string array with only one record - the result
* URL. If `TRUE`, result url is split into two
* parts and function return array with two items.
* @return \string[] Result URL address in array. If last argument is
* `FALSE` by default, this function returns only
* single item array with result URL. If last
* argument is `TRUE`, function returns result URL
* in two parts - domain part with base path and
* path part with query string.
*/
protected function urlAbsPartAndSplitByRequestedBasePath (\MvcCore\IRequest $request, $resultUrl, $splitUrl) {
/** @var $this \MvcCore\Route */
$doubleSlashPos = mb_strpos($resultUrl, '//');
$doubleSlashPos = $doubleSlashPos === FALSE
? 0
: $doubleSlashPos + 2;
if (!$splitUrl) {
$resultSchemePart = mb_substr($resultUrl, 0, $doubleSlashPos);
$resultAfterScheme = mb_substr($resultUrl, $doubleSlashPos);
$resultAfterScheme = str_replace('//', '/', $resultAfterScheme);
if ($this->flags[0] === static::FLAG_SCHEME_ANY) {
$resultUrl = $request->GetScheme() . '//' . $resultAfterScheme;
} else {
$resultUrl = $resultSchemePart . $resultAfterScheme;
}
return [$resultUrl];
} else {
$nextSlashPos = mb_strpos($resultUrl, '/', $doubleSlashPos);
if ($nextSlashPos === FALSE) {
$queryStringPos = mb_strpos($resultUrl, '?', $doubleSlashPos);
$baseUrlPartEndPos = $queryStringPos === FALSE
? mb_strlen($resultUrl)
: $queryStringPos;
} else {
$baseUrlPartEndPos = $nextSlashPos;
}
$requestedBasePath = $request->GetBasePath();
$basePathLength = mb_strlen($requestedBasePath);
if ($basePathLength > 0) {
$basePathPos = mb_strpos($resultUrl, $requestedBasePath, $baseUrlPartEndPos);
if ($basePathPos === $baseUrlPartEndPos)
$baseUrlPartEndPos += $basePathLength;
}
$basePart = mb_substr($resultUrl, 0, $baseUrlPartEndPos);
if ($this->flags[0] === static::FLAG_SCHEME_ANY)
$basePart = $request->GetScheme() . $basePart;
$pathAndQueryPart = mb_substr($resultUrl, $baseUrlPartEndPos);
$questionMarkPos = mb_strpos($pathAndQueryPart, '?');
if ($questionMarkPos === FALSE) {
$pathAndQueryPart = str_replace('//', '/', $pathAndQueryPart);
} else {
$pathAndQueryPart = str_replace('//', '/', mb_substr($pathAndQueryPart, 0, $questionMarkPos))
. mb_substr($pathAndQueryPart, $questionMarkPos);
}
return [$basePart, $pathAndQueryPart];
}
}
/**
* After final URL is completed and if there is contained no scheme, no
* domain part and no base path part in route pattern (or reverse), then make
* checks if it needs scheme part, domain part or base path part by global
* route flag property `absolute` or by given params. Then complete absolute
* part and return result URL as single array record or split result URL by
* base path end point.
* @param \MvcCore\Request $request
* A request object.
* @param string $resultUrl
* Result URL to split. Result URL still could
* contain domain part or base path replacements.
* @param array $domainParams
* Array with params for first URL part (scheme,
* domain, base path).
* @param bool $domainParamsFlag
* Route second int flag value without base path.
* @param bool $splitUrl
* Boolean value about to split completed result URL
* into two parts or not. Default is FALSE to return
* a string array with only one record - the result
* URL. If `TRUE`, result url is split into two
* parts and function return array with two items.
* @return \string[] Result URL address in array. If last argument is
* `FALSE` by default, this function returns only
* single item array with result URL. If last
* argument is `TRUE`, function returns result URL
* in two parts - domain part with base path and
* path part with query string.
*/
protected function urlAbsPartAndSplitByGlobalSwitchOrBasePath (\MvcCore\IRequest $request, $resultUrl, & $domainParams, $domainParamsFlag, $splitUrl) {
/** @var $this \MvcCore\Route */
$router = $this->router;
$basePathParamName = $router::URL_PARAM_BASEPATH;
$basePart = isset($domainParams[$basePathParamName])
? isset($domainParams[$basePathParamName])
: $request->GetBasePath();
// If there is `%basePath%` placeholder in reverse, put before `$basePart`
// what is before matched `%basePath%` placeholder and edit `$resultUrl`
// to use only part after `%basePath%` placeholder:
if ($domainParamsFlag) {
$placeHolderBasePath = static::PLACEHOLDER_BASEPATH;
$basePathPlaceHolderPos = mb_strpos($resultUrl, $placeHolderBasePath);
if ($basePathPlaceHolderPos !== FALSE) {
$basePart = mb_substr($resultUrl, 0, $basePathPlaceHolderPos) . $basePart;
$resultUrl = mb_substr($resultUrl, $basePathPlaceHolderPos + mb_strlen($placeHolderBasePath));
}
}
$absoluteParamName = $router::URL_PARAM_ABSOLUTE;
if (
$this->absolute || (
isset($domainParams[$absoluteParamName]) && $domainParams[$absoluteParamName]
)
)
$basePart = $request->GetDomainUrl() . $basePart;
$questionMarkPos = mb_strpos($resultUrl, '?');
if ($questionMarkPos === FALSE) {
$resultUrl = str_replace('//', '/', $resultUrl);
} else {
$resultUrl = str_replace('//', '/', mb_substr($resultUrl, 0, $questionMarkPos))
. mb_substr($resultUrl, $questionMarkPos);
}
if ($splitUrl) return [$basePart, $resultUrl];
return [$basePart . $resultUrl];
}
/**
* Return `TRUE` if there are any domain params or `absolute` boolean flag
* found in given `$params` array. All those domain params and possible
* `absolute` flag unset from given `$params` array and return it in result
* array as domain params. Keys as param name, values as domain param value.
* @param array $params
* @return array
*/
protected function urlGetAndRemoveDomainPercentageParams (array & $params = []) {
/** @var $this \MvcCore\Route */
static $domainPercentageParams = [];
$absolute = FALSE;
$router = $this->router;
$absoluteParamName = $router::URL_PARAM_ABSOLUTE;
$result = [];
if (!$domainPercentageParams) {
$domainPercentageParams = [
$router::URL_PARAM_HOST,
$router::URL_PARAM_DOMAIN,
$router::URL_PARAM_TLD,
$router::URL_PARAM_SLD,
$router::URL_PARAM_BASEPATH,
];
}
foreach ($domainPercentageParams as $domainPercentageParam) {
if (isset($params[$domainPercentageParam])) {
$absolute = TRUE;
$result[$domainPercentageParam] = $params[$domainPercentageParam];
unset($params[$domainPercentageParam]);
}
}
if ($absolute) {
$result[$absoluteParamName] = TRUE;
} else if (isset($params[$absoluteParamName])) {
$result[$absoluteParamName] = (bool) $params[$absoluteParamName];
unset($params[$absoluteParamName]);
}
return $result;
}
/**
* Correct last character in path element completed in `Url()` method by
* cached router configuration protected property
* `\MvcCore\Router::$trailingSlashBehaviour;`.
* @param string $urlPath
* @return string
*/
protected function & urlCorrectTrailingSlashBehaviour (& $urlPath) {
/** @var $this \MvcCore\Route */
$trailingSlashBehaviour = $this->_trailingSlashBehaviour ?: (
$this->_trailingSlashBehaviour = $this->router->GetTrailingSlashBehaviour()
);
$urlPathLength = mb_strlen($urlPath);
$lastCharIsSlash = $urlPathLength > 0 && mb_substr($urlPath, $urlPathLength - 1) === '/';
if (!$lastCharIsSlash && $trailingSlashBehaviour === \MvcCore\IRouter::TRAILING_SLASH_ALWAYS) {
$urlPath .= '/';
} else if ($lastCharIsSlash && $trailingSlashBehaviour === \MvcCore\IRouter::TRAILING_SLASH_REMOVE) {
$urlPath = mb_substr($urlPath, 0, $urlPathLength - 1);
}
if ($urlPath === '')
$urlPath = '/';
return $urlPath;
}
}