isStaticRoute($routeData)) { $this->addStaticRoute($httpMethod, $routeData, $handler); } else { $this->addVariableRoute($httpMethod, $routeData, $handler); } } /** * @return mixed[] */ public function getData() { if (empty($this->methodToRegexToRoutesMap)) { return [$this->staticRoutes, []]; } return [$this->staticRoutes, $this->generateVariableRouteData()]; } /** * @return mixed[] */ private function generateVariableRouteData() { $data = []; foreach ($this->methodToRegexToRoutesMap as $method => $regexToRoutesMap) { $chunkSize = $this->computeChunkSize(count($regexToRoutesMap)); $chunks = array_chunk($regexToRoutesMap, $chunkSize, true); $data[$method] = array_map([$this, 'processChunk'], $chunks); } return $data; } /** * @param int * @return int */ private function computeChunkSize($count) { $numParts = max(1, round($count / $this->getApproxChunkSize())); return (int) ceil($count / $numParts); } /** * @param mixed[] * @return bool */ private function isStaticRoute($routeData) { return count($routeData) === 1 && is_string($routeData[0]); } private function addStaticRoute($httpMethod, $routeData, $handler) { $routeStr = $routeData[0]; if (isset($this->staticRoutes[$httpMethod][$routeStr])) { throw new BadRouteException(sprintf( 'Cannot register two routes matching "%s" for method "%s"', $routeStr, $httpMethod )); } if (isset($this->methodToRegexToRoutesMap[$httpMethod])) { foreach ($this->methodToRegexToRoutesMap[$httpMethod] as $route) { if ($route->matches($routeStr)) { throw new BadRouteException(sprintf( 'Static route "%s" is shadowed by previously defined variable route "%s" for method "%s"', $routeStr, $route->regex, $httpMethod )); } } } $this->staticRoutes[$httpMethod][$routeStr] = $handler; } private function addVariableRoute($httpMethod, $routeData, $handler) { list($regex, $variables) = $this->buildRegexForRoute($routeData); if (isset($this->methodToRegexToRoutesMap[$httpMethod][$regex])) { throw new BadRouteException(sprintf( 'Cannot register two routes matching "%s" for method "%s"', $regex, $httpMethod )); } $this->methodToRegexToRoutesMap[$httpMethod][$regex] = new Route( $httpMethod, $handler, $regex, $variables ); } /** * @param mixed[] * @return mixed[] */ private function buildRegexForRoute($routeData) { $regex = ''; $variables = []; foreach ($routeData as $part) { if (is_string($part)) { $regex .= preg_quote($part, '~'); continue; } list($varName, $regexPart) = $part; if (isset($variables[$varName])) { throw new BadRouteException(sprintf( 'Cannot use the same placeholder "%s" twice', $varName )); } if ($this->regexHasCapturingGroups($regexPart)) { throw new BadRouteException(sprintf( 'Regex "%s" for parameter "%s" contains a capturing group', $regexPart, $varName )); } $variables[$varName] = $varName; $regex .= '(' . $regexPart . ')'; } return [$regex, $variables]; } /** * @param string * @return bool */ private function regexHasCapturingGroups($regex) { if (false === strpos($regex, '(')) { // Needs to have at least a ( to contain a capturing group return false; } // Semi-accurate detection for capturing groups return (bool) preg_match( "~\n (?:\n \(\?\(\n | \[ [^\]\\]* (?: \\ . [^\]\\]* )* \]\n | \\ .\n ) (*SKIP)(*FAIL) |\n \(\n (?!\n \? (?! <(?![!=]) | P< | ' )\n | \*\n )\n ~x", $regex ); } } __halt_compiler();----SIGNATURE:----jwGQ2GlCtcTFDsOjQ1TQcNbJSKa6MfP8v2oWIUZ2YQAcpP4oGJ37ydfC5ld73BP6vI30QfyHoe541H9xWEWImDI5uUgpWWbNmRtrRHYNmAMD+QlSIUyCq303u679Qq0fDGhNgwIebsKJyGqzGzs3I83fNAnqR/QVH8WdAItM2u69CdTM7p8X8HIeN584VzoIFWZUe6KsvYugVxLhsDWtfMR3jU6KvatDI1j06Jz9+dW0gEnUxB/3Sv6G+nB2LMqu5t2oiLAGlANbLh183thfXDachEq5TVGRDZlAPvKwBxODCKSnRtzUtWxo2rIKgS/N8z1UbbgnjicRhsVeJ7v1Fl1/p7GD8kVMQhtLwmX+CZeHb8VcSXrxFnLq63OPfLxCOE0lii20s1d6vpo2C4BnUKzAboYjF/njCv40YvebQaWYDY2DLn0JDWLIUA4MMvywuQHJEdgBtEK3A7KuPQ34KTx0AZiJe262RLo4EXLrF2n3AkYFzXL4PPUoF23kANfHAaEGZEaDwvmVNj65KS+/z3Lgp8smC7+I8OGEFg4kFUpPOl2KwDORiTUIjZOuyEF/PKuSUGQFYXIMbkdsKAo4p4lMh0WshQRpSpCT/+lH3hFRFRcOyrsMTcpL4xFy60pjIefgw8+UdIPYs5vQetKrHINFCziseuu2UL17ec55RMM=----ATTACHMENT:----NzEyMTI3MTE2NzgzMzA1MyAyNTQ0NjQ4NDkzMDQwMDc1IDU2MzU5NTU2OTc2MDg4Nzg=