/** * Matches a request against a route collection. * * @param RouteCollectionInterface $routeCollection * @param ServerRequestInterface $request * @param int $pathOffset * @param array $parentParams * @return MatchResult|null * @throws UnexpectedValueException */ public static function matchRouteCollection(RouteCollectionInterface $routeCollection, ServerRequestInterface $request, $pathOffset, array $parentParams) { $methodFailureResult = null; $schemeFailureResult = null; foreach ($routeCollection as $name => $route) { if (null === ($matchResult = $route->match($request, $pathOffset))) { continue; } if ($matchResult->isSuccess()) { return MatchResult::fromChildMatch($matchResult, $parentParams, $name); } if ($matchResult->isMethodFailure()) { if (null === $methodFailureResult) { $methodFailureResult = $matchResult; } else { $methodFailureResult = MatchResult::mergeMethodFailures($methodFailureResult, $matchResult); } continue; } if ($matchResult->isSchemeFailure()) { $schemeFailureResult = $schemeFailureResult ?: $matchResult; continue; } return $matchResult; } if (null !== $schemeFailureResult) { return $schemeFailureResult; } if (null !== $methodFailureResult) { return $methodFailureResult; } return null; }
public function testMethodNotAllowedResultsAreMerged() { $firstMatchResult = MatchResult::fromMethodFailure(['GET']); $secondMatchResult = MatchResult::fromMethodFailure(['POST']); $matchResult = RouteCollectionMatcher::matchRouteCollection($this->buildRouteCollection([$firstMatchResult, $secondMatchResult]), $this->prophesize(ServerRequestInterface::class)->reveal(), 0, []); $this->assertInstanceOf(MatchResult::class, $matchResult); $this->assertTrue($matchResult->isMethodFailure()); $this->assertEquals(['GET', 'POST'], $matchResult->getAllowedMethods()); }
public function testMergeMethodFailuresWithIncompatibleMatchResults() { $this->setExpectedException(DomainException::class, 'Both match results must be method failures'); MatchResult::mergeMethodFailures(MatchResult::fromMatchFailure(), MatchResult::fromMatchFailure()); }
/** * Merges two method failure match results. * * @param self $firstMatchResult * @param self $secondMatchResult * @return self * @throws DomainException */ public static function mergeMethodFailures(self $firstMatchResult, self $secondMatchResult) { if (!$firstMatchResult->isMethodFailure() || !$secondMatchResult->isMethodFailure()) { throw new DomainException('Both match results must be method failures'); } return self::fromMethodFailure(array_unique(array_merge($firstMatchResult->getAllowedMethods(), $secondMatchResult->getAllowedMethods()))); }
public function testIncompletePathMatchWithChildMatch() { $matchResult = $this->buildRoute(['path_parser' => $this->getIncompletePathParser(), 'children' => $this->buildChildren([MatchResult::fromSuccess(['baz' => 'bat'])])])->match($this->buildRequest(), 4); $this->assertInstanceOf(MatchResult::class, $matchResult); $this->assertTrue($matchResult->isSuccess()); $this->assertEquals(['foo' => 'bar', 'baz' => 'bat'], $matchResult->getParams()); }
/** * {@inheritdoc} * * @throws UnexpectedValueException */ public function match(ServerRequestInterface $request) { $basePathLength = strlen($this->baseUri['path']); return RouteCollectionMatcher::matchRouteCollection($this->routeCollection, $request, $basePathLength, []) ?: MatchResult::fromMatchFailure(); }
/** * {@inheritdoc} * * @throws Exception\UnexpectedValueException */ public function match(ServerRequestInterface $request, $pathOffset) { $uri = $request->getUri(); $params = $this->defaults; // Verify scheme first, if set. if (true === $this->secure && 'https' !== $uri->getScheme()) { return MatchResult::fromSchemeFailure($uri->withScheme('https')); } elseif (false === $this->secure && 'http' !== $uri->getScheme()) { return MatchResult::fromSchemeFailure($uri->withScheme('http')); } // Then match hostname, if parser is set. if (null !== $this->hostnameParser) { $hostnameResult = $this->hostnameParser->parse($uri->getHost(), 0); if (null === $hostnameResult || strlen($uri->getHost()) !== $hostnameResult->getMatchLength()) { return null; } $params = $hostnameResult->getParams() + $params; } // Then match port, if set. if (null !== $this->port) { $port = $uri->getPort() ?: ('http' === $uri->getScheme() ? 80 : 443); if ($port !== $this->port) { return null; } } // Next match the path. $completePathMatched = false; if (null !== $this->pathParser) { if (null === ($pathResult = $this->pathParser->parse($uri->getPath(), $pathOffset))) { return null; } $pathOffset += $pathResult->getMatchLength(); $completePathMatched = $pathOffset === strlen($uri->getPath()); $params = $pathResult->getParams() + $params; } if ($completePathMatched) { if (null === $this->methods || in_array($request->getMethod(), $this->methods)) { return MatchResult::fromSuccess($params); } if (empty($this->methods)) { // Special case: when no methods are defined at all, this route may simply not terminate. return null; } return MatchResult::fromMethodFailure($this->methods); } // The path was not completely matched yet, so we check the children. if (null === $this->children) { return null; } return RouteCollectionMatcher::matchRouteCollection($this->children, $request, $pathOffset, $params); }