/** * @test */ public function routePartValueIsNullAfterUnsuccessfulResolve() { $this->dynamicRoutPart->setName('foo'); $routeValues = ['foo' => 'bar']; $this->assertTrue($this->dynamicRoutPart->resolve($routeValues)); $routeValues = []; $this->assertFalse($this->dynamicRoutPart->resolve($routeValues)); $this->assertNull($this->dynamicRoutPart->getValue(), 'Dynamic Route Part value should be NULL when call to resolve() was not successful.'); }
/** * Iterates through all segments in $this->uriPattern and creates * appropriate RoutePart instances. * * @return void * @throws InvalidRoutePartHandlerException * @throws InvalidUriPatternException */ public function parse() { if ($this->isParsed || $this->uriPattern === null || $this->uriPattern === '') { return; } $this->routeParts = []; $currentRoutePartIsOptional = false; if (substr($this->uriPattern, -1) === '/') { throw new InvalidUriPatternException('The URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" ends with a slash, which is not allowed. You can put the trailing slash in brackets to make it optional.', 1234782997); } if ($this->uriPattern[0] === '/') { throw new InvalidUriPatternException('The URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" starts with a slash, which is not allowed.', 1234782983); } $matches = []; preg_match_all(self::PATTERN_EXTRACTROUTEPARTS, $this->uriPattern, $matches, PREG_SET_ORDER); /** @var $lastRoutePart RoutePartInterface */ $lastRoutePart = null; foreach ($matches as $match) { $routePartType = empty($match['dynamic']) ? self::ROUTEPART_TYPE_STATIC : self::ROUTEPART_TYPE_DYNAMIC; $routePartName = $match['content']; if (!empty($match['optionalStart'])) { if ($lastRoutePart !== null && $lastRoutePart->isOptional()) { throw new InvalidUriPatternException('the URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" contains successive optional Route sections, which is not allowed.', 1234562050); } $currentRoutePartIsOptional = true; } $routePart = null; switch ($routePartType) { case self::ROUTEPART_TYPE_DYNAMIC: if ($lastRoutePart instanceof DynamicRoutePartInterface) { throw new InvalidUriPatternException('the URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" contains successive Dynamic Route Parts, which is not allowed.', 1218446975); } if (isset($this->routePartsConfiguration[$routePartName]['handler'])) { $routePart = $this->objectManager->get($this->routePartsConfiguration[$routePartName]['handler']); if (!$routePart instanceof DynamicRoutePartInterface) { throw new InvalidRoutePartHandlerException(sprintf('routePart handlers must implement "%s" in route "%s"', DynamicRoutePartInterface::class, $this->getName()), 1218480972); } } elseif (isset($this->routePartsConfiguration[$routePartName]['objectType'])) { $routePart = new IdentityRoutePart(); $routePart->setObjectType($this->routePartsConfiguration[$routePartName]['objectType']); if (isset($this->routePartsConfiguration[$routePartName]['uriPattern'])) { $routePart->setUriPattern($this->routePartsConfiguration[$routePartName]['uriPattern']); } } else { $routePart = new DynamicRoutePart(); } $routePartDefaultValue = ObjectAccess::getPropertyPath($this->defaults, $routePartName); if ($routePartDefaultValue !== null) { $routePart->setDefaultValue($routePartDefaultValue); } break; case self::ROUTEPART_TYPE_STATIC: $routePart = new StaticRoutePart(); if ($lastRoutePart !== null && $lastRoutePart instanceof DynamicRoutePartInterface) { /** @var DynamicRoutePartInterface $lastRoutePart */ $lastRoutePart->setSplitString($routePartName); } } $routePart->setName($routePartName); if ($currentRoutePartIsOptional) { $routePart->setOptional(true); if ($routePart instanceof DynamicRoutePartInterface && !$routePart->hasDefaultValue()) { throw new InvalidRouteSetupException(sprintf('There is no default value specified for the optional route part "{%s}" of route "%s", but all dynamic optional route parts need a default.', $routePartName, $this->getName()), 1477140679); } } $routePart->setLowerCase($this->lowerCase); if (isset($this->routePartsConfiguration[$routePartName]['options'])) { $routePart->setOptions($this->routePartsConfiguration[$routePartName]['options']); } if (isset($this->routePartsConfiguration[$routePartName]['toLowerCase'])) { $routePart->setLowerCase($this->routePartsConfiguration[$routePartName]['toLowerCase']); } $this->routeParts[] = $routePart; if (!empty($match['optionalEnd'])) { if (!$currentRoutePartIsOptional) { throw new InvalidUriPatternException('The URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" contains an unopened optional section.', 1234564495); } $currentRoutePartIsOptional = false; } $lastRoutePart = $routePart; } if ($currentRoutePartIsOptional) { throw new InvalidUriPatternException('The URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" contains an unterminated optional section.', 1234563922); } $this->isParsed = true; }
/** * Returns the first part of $routePath that should be evaluated in matchValue(). * If no split string is set (route part is the last in the routes uriPattern), the complete $routePart is returned. * Otherwise the part is returned that matches the specified uriPattern of this route part. * * @param string $routePath The request path to be matched * @return string value to match, or an empty string if $routePath is empty, split string was not found or uriPattern could not be matched * @api */ protected function findValueToMatch($routePath) { if (!isset($routePath) || $routePath === '' || $routePath[0] === '/') { return ''; } if ($this->getUriPattern() === '') { return parent::findValueToMatch($routePath); } $regexPattern = preg_quote($this->getUriPattern(), '/'); $regexPattern = preg_replace('/\\\\{[^}]+\\\\}/', '[^\\/]+', $regexPattern); if ($this->splitString !== '') { $regexPattern .= '(?=' . preg_quote($this->splitString, '/') . ')'; } $matches = []; preg_match('/^' . $regexPattern . '/', trim($routePath, '/'), $matches); return isset($matches[0]) ? $matches[0] : ''; }