/**
  * Dispatches a signal by calling the registered Slot methods
  *
  * @param string $signalClassName Name of the class containing the signal
  * @param string $signalMethodName Method name of the signal
  * @param array $signalArguments arguments passed to the signal method
  * @return void
  * @throws \F3\FLOW3\SignalSlot\Exception\InvalidSlotException if the slot is not valid
  * @author Robert Lemke <*****@*****.**>
  * @api
  */
 public function dispatch($signalClassName, $signalMethodName, array $signalArguments)
 {
     if (!isset($this->slots[$signalClassName][$signalMethodName])) {
         return;
     }
     $this->systemLogger->log(sprintf('Dispatching signal %s::%s ...', $signalClassName, $signalMethodName), LOG_DEBUG);
     foreach ($this->slots[$signalClassName][$signalMethodName] as $slotInformation) {
         if (isset($slotInformation['object'])) {
             $object = $slotInformation['object'];
         } else {
             if (!$this->objectManager->isObjectRegistered($slotInformation['class'])) {
                 throw new \F3\FLOW3\SignalSlot\Exception\InvalidSlotException('The given class "' . $slotInformation['class'] . '" is not a registered object.', 1245673367);
             }
             $object = $this->objectManager->getObject($slotInformation['class']);
         }
         $slotArguments = $signalArguments;
         if ($slotInformation['omitSignalInformation'] !== TRUE) {
             array_unshift($slotArguments, $signalClassName . '::' . $signalMethodName);
         }
         $this->systemLogger->log(sprintf('  to slot %s::%s.', get_class($object), $slotInformation['method']), LOG_DEBUG);
         if (!method_exists($object, $slotInformation['method'])) {
             throw new \F3\FLOW3\SignalSlot\Exception\InvalidSlotException('The slot method ' . get_class($object) . '->' . $slotInformation['method'] . '() does not exist.', 1245673368);
         }
         call_user_func_array(array($object, $slotInformation['method']), $slotArguments);
     }
 }
 /**
  * Commits new objects and changes to objects in the current persistence
  * session into the backend
  *
  * @return void
  * @author Robert Lemke <*****@*****.**>
  * @author Karsten Dambekalns <*****@*****.**>
  * @api
  */
 public function persistAll()
 {
     $aggregateRootObjects = new \SplObjectStorage();
     $deletedEntities = new \SplObjectStorage();
     // fetch and inspect objects from all known repositories
     $repositoryClassNames = $this->reflectionService->getAllImplementationClassNamesForInterface('F3\\FLOW3\\Persistence\\RepositoryInterface');
     foreach ($repositoryClassNames as $repositoryClassName) {
         $repository = $this->objectManager->getObject($repositoryClassName);
         $aggregateRootObjects->addAll($repository->getAddedObjects());
         $deletedEntities->addAll($repository->getRemovedObjects());
     }
     $aggregateRootObjects->addAll($this->persistenceSession->getReconstitutedObjects());
     // hand in only aggregate roots, leaving handling of subobjects to
     // the underlying storage layer
     $this->backend->setAggregateRootObjects($aggregateRootObjects);
     $this->backend->setDeletedEntities($deletedEntities);
     $this->backend->commit();
     // this needs to unregister more than just those, as at least some of
     // the subobjects are supposed to go away as well...
     // OTOH those do no harm, changes to the unused ones should not happen,
     // so all they do is eat some memory.
     foreach ($deletedEntities as $deletedEntity) {
         $this->persistenceSession->unregisterReconstitutedObject($deletedEntity);
     }
 }
 /**
  * Adds a custom filter to the poincut filter composite
  *
  * @param string $operator The operator
  * @param string $filterObjectName Object Name of the custom filter (value of the designator)
  * @param \F3\FLOW3\AOP\Pointcut\PointcutFilterComposite $pointcutFilterComposite An instance of the pointcut filter composite. The result (ie. the custom filter) will be added to this composite object.
  * @return void
  * @author Robert Lemke <*****@*****.**>
  */
 protected function parseDesignatorFilter($operator, $filterObjectName, \F3\FLOW3\AOP\Pointcut\PointcutFilterComposite $pointcutFilterComposite)
 {
     $customFilter = $this->objectManager->getObject($filterObjectName);
     if (!$customFilter instanceof \F3\FLOW3\AOP\Pointcut\PointcutFilterInterface) {
         throw new \F3\FLOW3\AOP\Exception\InvalidPointcutExpressionException('Invalid custom filter: "' . $filterObjectName . '" does not implement the required PoincutFilterInterface.', 1231871755);
     }
     $pointcutFilterComposite->addFilter($operator, $customFilter);
 }
 /**
  * Creates and sets the configured access decision voters
  *
  * @param array $voterClassNames Array of access decision voter class names
  * @return void
  * @author Andreas Förthner <*****@*****.**>
  */
 protected function createAccessDecisionVoters(array $voterClassNames)
 {
     foreach ($voterClassNames as $voterClassName) {
         if (!$this->objectManager->isObjectRegistered($voterClassName)) {
             throw new \F3\FLOW3\Security\Exception\VoterNotFoundException('No voter of type ' . $voterClassName . ' found!', 1222267934);
         }
         $voter = $this->objectManager->getObject($voterClassName);
         if (!$voter instanceof \F3\FLOW3\Security\Authorization\AccessDecisionVoterInterface) {
             throw new \F3\FLOW3\Security\Exception\VoterNotFoundException('The found voter class did not implement \\F3\\FLOW3\\Security\\Authorization\\AccessDecisionVoterInterface', 1222268008);
         }
         $this->accessDecisionVoters[] = $voter;
     }
 }
 /**
  * Maps arguments delivered by the request object to the local controller arguments.
  *
  * @return void
  * @author Robert Lemke <*****@*****.**>
  */
 protected function mapRequestArgumentsToControllerArguments()
 {
     $optionalArgumentNames = array();
     $allArgumentNames = $this->arguments->getArgumentNames();
     foreach ($allArgumentNames as $argumentName) {
         if ($this->arguments[$argumentName]->isRequired() === FALSE) {
             $optionalArgumentNames[] = $argumentName;
         }
     }
     $validator = $this->objectManager->getObject('F3\\FLOW3\\MVC\\Controller\\ArgumentsValidator');
     $this->propertyMapper->mapAndValidate($allArgumentNames, $this->request->getArguments(), $this->arguments, $optionalArgumentNames, $validator);
     $this->argumentsMappingResults = $this->propertyMapper->getMappingResults();
 }
 /**
  * Analyzes the raw request and tries to find a request handler which can handle
  * it. If none is found, an exception is thrown.
  *
  * @return \F3\FLOW3\MVC\RequestHandler A request handler
  * @throws \F3\FLOW3\MVC\Exception
  * @author Robert Lemke <*****@*****.**>
  */
 public function resolveRequestHandler()
 {
     $availableRequestHandlerClassNames = $this->reflectionService->getAllImplementationClassNamesForInterface('F3\\FLOW3\\MVC\\RequestHandlerInterface');
     $suitableRequestHandlers = array();
     foreach ($availableRequestHandlerClassNames as $requestHandlerClassName) {
         if (!$this->objectManager->isObjectRegistered($requestHandlerClassName)) {
             continue;
         }
         $requestHandler = $this->objectManager->getObject($requestHandlerClassName);
         if ($requestHandler->canHandleRequest()) {
             $priority = $requestHandler->getPriority();
             if (isset($suitableRequestHandlers[$priority])) {
                 throw new \F3\FLOW3\MVC\Exception('More than one request handler with the same priority can handle the request, but only one handler may be active at a time!', 1176475350);
             }
             $suitableRequestHandlers[$priority] = $requestHandler;
         }
     }
     if (count($suitableRequestHandlers) === 0) {
         throw new \F3\FLOW3\MVC\Exception('No suitable request handler found.', 1205414233);
     }
     ksort($suitableRequestHandlers);
     return array_pop($suitableRequestHandlers);
 }
 /**
  * Checks, resolves and injects dependencies as properties through calling the setter methods or setting
  * properties directly through reflection.
  *
  * @param array $properties Array of \F3\FLOW3\Object\Configuration\ConfigurationProperty for the current object
  * @param object $object The recently created instance of the current object. Dependencies will be injected to it.
  * @return void
  * @author Robert Lemke <*****@*****.**>
  */
 protected function injectProperties($properties, $object)
 {
     foreach ($properties as $propertyName => $property) {
         $propertyValue = $property->getValue();
         switch ($property->getType()) {
             case \F3\FLOW3\Object\Configuration\ConfigurationProperty::PROPERTY_TYPES_OBJECT:
                 if ($propertyValue instanceof \F3\FLOW3\Object\Configuration\Configuration) {
                     $preparedValue = $this->createObject($propertyValue->getObjectName(), $propertyValue);
                 } else {
                     if (strpos($propertyValue, '.') !== FALSE) {
                         $settingPath = explode('.', $propertyValue);
                         $settings = $this->configurationManager->getConfiguration(\F3\FLOW3\Configuration\ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, array_shift($settingPath));
                         $propertyValue = \F3\FLOW3\Utility\Arrays::getValueByPath($settings, $settingPath);
                     }
                     $preparedValue = $this->objectManager->getObject($propertyValue);
                 }
                 break;
             case \F3\FLOW3\Object\Configuration\ConfigurationProperty::PROPERTY_TYPES_STRAIGHTVALUE:
                 $preparedValue = $propertyValue;
                 break;
             case \F3\FLOW3\Object\Configuration\ConfigurationProperty::PROPERTY_TYPES_SETTING:
                 if (strpos($propertyValue, '.') !== FALSE) {
                     $settingPath = explode('.', $propertyValue);
                     $settings = $this->configurationManager->getConfiguration(\F3\FLOW3\Configuration\ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, array_shift($settingPath));
                     $preparedValue = \F3\FLOW3\Utility\Arrays::getValueByPath($settings, $settingPath);
                 } else {
                     $preparedValue = $this->configurationManager->getConfiguration(\F3\FLOW3\Configuration\ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, $propertyValue);
                 }
                 break;
         }
         $setterMethodName = 'inject' . ucfirst($propertyName);
         if (method_exists($object, $setterMethodName)) {
             $object->{$setterMethodName}($preparedValue);
             continue;
         }
         $setterMethodName = 'set' . ucfirst($propertyName);
         if (method_exists($object, $setterMethodName)) {
             $object->{$setterMethodName}($preparedValue);
             continue;
         }
         if (property_exists($object, $propertyName)) {
             $propertyReflection = new \ReflectionProperty($object, $propertyName);
             $propertyReflection->setAccessible(TRUE);
             $propertyReflection->setValue($object, $preparedValue);
         }
     }
 }
 /**
  * Transforms strings with UUIDs or arrays with UUIDs/identity properties
  * into the requested type, if possible.
  *
  * @param mixed $propertyValue The value to transform, string or array
  * @param string $targetType The type to transform to
  * @param string $propertyName In case of an error we add this to the error message
  * @return object The object, when no transformation was possible this may return NULL as well
  */
 protected function transformToObject($propertyValue, $targetType, $propertyName)
 {
     if (is_string($propertyValue) && preg_match(self::PATTERN_MATCH_UUID, $propertyValue) === 1) {
         $object = $this->persistenceManager->getObjectByIdentifier($propertyValue);
         if ($object === FALSE) {
             $this->mappingResults->addError($this->objectManager->getObject('F3\\FLOW3\\Error\\Error', 'Querying the repository for the specified object with UUID ' . $propertyValue . ' was not successful.', 1249379517), $propertyName);
         }
     } elseif (is_array($propertyValue)) {
         if (isset($propertyValue['__identity'])) {
             $existingObject = is_array($propertyValue['__identity']) ? $this->findObjectByIdentityProperties($propertyValue['__identity'], $targetType) : $this->persistenceManager->getObjectByIdentifier($propertyValue['__identity']);
             if ($existingObject === FALSE) {
                 throw new \F3\FLOW3\Property\Exception\TargetNotFoundException('Querying the repository for the specified object was not successful.', 1237305720);
             }
             unset($propertyValue['__identity']);
             if (count($propertyValue) === 0) {
                 $object = $existingObject;
             } elseif ($existingObject !== NULL) {
                 $newObject = clone $existingObject;
                 if ($this->map(array_keys($propertyValue), $propertyValue, $newObject)) {
                     $object = $newObject;
                 }
             }
         } else {
             if (isset($this->objectConverters[$targetType])) {
                 $conversionResult = $this->objectConverters[$targetType]->convertFrom($propertyValue);
                 if ($conversionResult instanceof \F3\FLOW3\Error\Error) {
                     $this->mappingResults->addError($conversionResult, $propertyName);
                     return NULL;
                 } elseif (is_object($conversionResult) || $conversionResult === NULL) {
                     return $conversionResult;
                 }
             }
             $newObject = $this->objectManager->getObject($targetType);
             if ($this->map(array_keys($propertyValue), $propertyValue, $newObject)) {
                 return $newObject;
             }
             throw new \F3\FLOW3\Property\Exception\InvalidTargetException('Values could not be mapped to new object of type ' . $targetType . ' for property "' . $propertyName . '". (Map errors: ' . implode(' - ', $this->mappingResults->getErrors()) . ')', 1259770027);
         }
     } else {
         throw new \InvalidArgumentException('transformToObject() accepts only strings and arrays.', 1251814355);
     }
     return $object;
 }
 /**
  * Traverses the Tests directory of the given package and returns an
  * array of filenames (including path) of all files ending with "Test.php".
  *
  * @return array Filenames of all found testcase files
  * @author Robert Lemke <*****@*****.**>
  * @author Karsten Dambekalns <*****@*****.**>
  */
 protected function getTestcaseFilenames()
 {
     $packageManager = $this->objectManager->getObject('F3\\FLOW3\\Package\\PackageManagerInterface');
     $packages = array();
     $testcaseFilenames = array(self::TYPE_UNIT => array(), self::TYPE_INTEGRATION => array(), self::TYPE_SYSTEM => array());
     $testcaseClassNameMatches = array();
     preg_match('/F3\\\\([^\\\\]*)\\\\(.*)/', $this->testcaseClassName, $testcaseClassNameMatches);
     if (count($testcaseClassNameMatches) === 3) {
         $this->testcaseClassName = $testcaseClassNameMatches[2];
         if ($testcaseClassNameMatches[1] === '.*') {
             $packages = $packageManager->getActivePackages();
         } elseif ($packageManager->isPackageActive($testcaseClassNameMatches[1])) {
             $packages = array($packageManager->getPackage($testcaseClassNameMatches[1]));
         }
     } elseif ($this->packageKey == '*') {
         $packages = $packageManager->getActivePackages();
         $this->testcaseClassName = '.*Test';
     } elseif ($packageManager->isPackageActive($this->packageKey)) {
         $packages = array($packageManager->getPackage($this->packageKey));
         $this->testcaseClassName = '.*Test';
     }
     shuffle($packages);
     foreach ($packages as $package) {
         if (in_array($package->getPackageKey(), $this->testBlacklist)) {
             continue;
         }
         foreach (array(self::TYPE_UNIT => \F3\FLOW3\Package\Package::DIRECTORY_TESTS_UNIT, self::TYPE_INTEGRATION => \F3\FLOW3\Package\Package::DIRECTORY_TESTS_INTEGRATION, self::TYPE_SYSTEM => \F3\FLOW3\Package\Package::DIRECTORY_TESTS_SYSTEM) as $type => $directory) {
             $testPath = $package->getPackagePath() . $directory;
             if (is_dir($testPath)) {
                 try {
                     $testsDirectoryIterator = new \RecursiveDirectoryIterator($testPath);
                     $testcaseFilenames[$type] = $this->readDirectories($testcaseFilenames[$type], $testsDirectoryIterator);
                     \PHPUnit_Util_Filter::removeDirectoryFromFilter($package->getPackagePath() . 'Classes');
                 } catch (\Exception $exception) {
                     throw new \RuntimeException($exception->getMessage(), 1170236926);
                 }
             }
             shuffle($testcaseFilenames[$type]);
         }
     }
     return $testcaseFilenames;
 }
 /**
  * Builds the provider and token objects based on the given configuration
  *
  * @param array $providerConfigurations The configured provider settings
  * @return void
  * @author Andreas Förthner <*****@*****.**>
  */
 protected function buildProvidersAndTokensFromConfiguration(array $providerConfigurations)
 {
     foreach ($providerConfigurations as $providerName => $providerConfiguration) {
         if (!is_array($providerConfiguration) || !isset($providerConfiguration['providerClass'])) {
             throw new \F3\FLOW3\Security\Exception\InvalidAuthenticationProviderException('The configured authentication provider "' . $providerConfiguration['providerClass'] . '" could not be found!', 1248209521);
         }
         $providerObjectName = $this->providerResolver->resolveProviderClass((string) $providerConfiguration['providerClass']);
         if ($providerObjectName === NULL) {
             throw new \F3\FLOW3\Security\Exception\InvalidAuthenticationProviderException('The configured authentication provider "' . $providerConfiguration['providerClass'] . '" could not be found!', 1237330453);
         }
         $providerOptions = array();
         if (isset($providerConfiguration['options']) && is_array($providerConfiguration['options'])) {
             $providerOptions = $providerConfiguration['options'];
         }
         $providerInstance = $this->objectManager->getObject($providerObjectName, $providerName, $providerOptions);
         $this->providers[] = $providerInstance;
         foreach ($providerInstance->getTokenClassNames() as $tokenClassName) {
             $tokenInstance = $this->objectManager->getObject($tokenClassName);
             $tokenInstance->setAuthenticationProviderName($providerName);
             $this->tokens[] = $tokenInstance;
         }
         if (isset($providerConfiguration['requestPatterns']) && is_array($providerConfiguration['requestPatterns'])) {
             $requestPatterns = array();
             foreach ($providerConfiguration['requestPatterns'] as $patternType => $patternConfiguration) {
                 $requestPattern = $this->objectManager->getObject($this->requestPatternResolver->resolveRequestPatternClass($patternType));
                 $requestPattern->setPattern($patternConfiguration);
                 $requestPatterns[] = $requestPattern;
             }
             $tokenInstance->setRequestPatterns($requestPatterns);
         }
         if (isset($providerConfiguration['entryPoint']) && is_array($providerConfiguration['entryPoint'])) {
             reset($providerConfiguration['entryPoint']);
             $entryPointObjectName = key($providerConfiguration['entryPoint']);
             $entryPoint = $this->objectManager->getObject($this->entryPointResolver->resolveEntryPointClass($entryPointObjectName));
             $entryPoint->setOptions($providerConfiguration['entryPoint'][$entryPointObjectName]);
             $tokenInstance->setAuthenticationEntryPoint($entryPoint);
         }
     }
 }
 /**
  * (For now) evaluates the package configuration
  *
  * @param \F3\FLOW3\Package\PackageInterface $package The package
  * @param array $packageConfiguration The configuration to evaluate
  * @return void
  * @author Robert Lemke <*****@*****.**>
  * @see initializePackages()
  * @todo needs refactoring and be moved to elsewhere (package manager)
  */
 protected function evaluatePackageConfiguration(\F3\FLOW3\Package\PackageInterface $package, array $packageConfiguration)
 {
     if (isset($packageConfiguration['classLoader'])) {
         if (isset($packageConfiguration['classLoader']['specialClassNameAndPaths'])) {
             $classLoader = $this->objectManager->getObject('F3\\FLOW3\\Resource\\ClassLoader');
             foreach ($packageConfiguration['classLoader']['specialClassNameAndPaths'] as $className => $classFilePathAndName) {
                 $classFilePathAndName = str_replace('%PATH_PACKAGE%', $package->getPackagePath(), $classFilePathAndName);
                 $classFilePathAndName = str_replace('%PATH_PACKAGE_CLASSES%', $package->getClassesPath(), $classFilePathAndName);
                 $classFilePathAndName = str_replace('%PATH_PACKAGE_RESOURCES%', $package->getResourcesPath(), $classFilePathAndName);
                 $classLoader->setSpecialClassNameAndPath($className, $classFilePathAndName);
             }
         }
         if (isset($packageConfiguration['classLoader']['includePaths'])) {
             foreach ($packageConfiguration['classLoader']['includePaths'] as $includePath) {
                 $includePath = str_replace('%PATH_PACKAGE%', $package->getPackagePath(), $includePath);
                 $includePath = str_replace('%PATH_PACKAGE_CLASSES%', $package->getClassesPath(), $includePath);
                 $includePath = str_replace('%PATH_PACKAGE_RESOURCES%', $package->getResourcesPath(), $includePath);
                 $includePath = str_replace('/', DIRECTORY_SEPARATOR, $includePath);
                 set_include_path($includePath . PATH_SEPARATOR . get_include_path());
             }
         }
     }
 }
 /**
  * Builds a base validator conjunction for the given data type.
  *
  * The base validation rules are those which were declared directly in a class (typically
  * a model) through some @validate annotations on properties.
  *
  * Additionally, if a custom validator was defined for the class in question, it will be added
  * to the end of the conjunction. A custom validator is found if it follows the naming convention
  * "Replace '\Model\' by '\Validator\' and append "Validator".
  *
  * Example: $dataType is F3\Foo\Domain\Model\Quux, then the Validator will be found if it has the
  * name F3\Foo\Domain\Validator\QuuxValidator
  *
  * @param string $dataType The data type to build the validation conjunction for. Needs to be the fully qualified object name.
  * @return F3\FLOW3\Validation\Validator\ConjunctionValidator The validator conjunction or NULL
  * @author Robert Lemke <*****@*****.**>
  * @author Sebastian Kurfürst <*****@*****.**>
  */
 protected function buildBaseValidatorConjunction($dataType)
 {
     $validatorConjunction = $this->objectManager->getObject('F3\\FLOW3\\Validation\\Validator\\ConjunctionValidator');
     // Model based validator
     if (class_exists($dataType)) {
         $validatorCount = 0;
         $objectValidator = $this->createValidator('F3\\FLOW3\\Validation\\Validator\\GenericObjectValidator');
         foreach ($this->reflectionService->getClassPropertyNames($dataType) as $classPropertyName) {
             $classPropertyTagsValues = $this->reflectionService->getPropertyTagsValues($dataType, $classPropertyName);
             if (!isset($classPropertyTagsValues['validate'])) {
                 continue;
             }
             foreach ($classPropertyTagsValues['validate'] as $validateValue) {
                 $parsedAnnotation = $this->parseValidatorAnnotation($validateValue);
                 foreach ($parsedAnnotation['validators'] as $validatorConfiguration) {
                     $newValidator = $this->createValidator($validatorConfiguration['validatorName'], $validatorConfiguration['validatorOptions']);
                     if ($newValidator === NULL) {
                         throw new \F3\FLOW3\Validation\Exception\NoSuchValidatorException('Invalid validate annotation in ' . $dataType . '::' . $classPropertyName . ': Could not resolve class name for  validator "' . $validatorConfiguration['validatorName'] . '".', 1241098027);
                     }
                     $objectValidator->addPropertyValidator($classPropertyName, $newValidator);
                     $validatorCount++;
                 }
             }
         }
         if ($validatorCount > 0) {
             $validatorConjunction->addValidator($objectValidator);
         }
     }
     // Custom validator for the class
     $possibleValidatorClassName = str_replace('\\Model\\', '\\Validator\\', $dataType) . 'Validator';
     $customValidator = $this->createValidator($possibleValidatorClassName);
     if ($customValidator !== NULL) {
         $validatorConjunction->addValidator($customValidator);
     }
     return $validatorConjunction;
 }
 /**
  * Set a filter
  *
  * @param mixed $filter Object name of a filter or the actual filter object
  * @return \F3\FLOW3\MVC\Controller\Argument Returns $this (used for fluent interface)
  * @author Andreas Förthner <*****@*****.**>
  */
 public function setFilter($filter)
 {
     $this->filter = $filter instanceof \F3\FLOW3\Validation\Filter\FilterInterface ? $filter : $this->objectManager->getObject($filter);
     return $this;
 }
 /**
  * Iterates through all segments in $this->uriPattern and creates
  * appropriate RoutePart instances.
  *
  * @return void
  * @author Bastian Waidelich <*****@*****.**>
  */
 public function parse()
 {
     if ($this->isParsed || $this->uriPattern === NULL || $this->uriPattern === '') {
         return;
     }
     $this->routeParts = array();
     $currentRoutePartIsOptional = FALSE;
     if (substr($this->uriPattern, -1) === '/') {
         throw new \F3\FLOW3\MVC\Exception\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 \F3\FLOW3\MVC\Exception\InvalidUriPatternException('The URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" starts with a slash, which is not allowed.', 1234782983);
     }
     $matches = array();
     preg_match_all(self::PATTERN_EXTRACTROUTEPARTS, $this->uriPattern, $matches, PREG_SET_ORDER);
     $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 \F3\FLOW3\MVC\Exception\InvalidUriPatternException('the URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" contains succesive optional Route sections, which is not allowed.', 1234562050);
             }
             $currentRoutePartIsOptional = TRUE;
         }
         $routePart = NULL;
         switch ($routePartType) {
             case self::ROUTEPART_TYPE_DYNAMIC:
                 if ($lastRoutePart instanceof \F3\FLOW3\MVC\Web\Routing\DynamicRoutePartInterface) {
                     throw new \F3\FLOW3\MVC\Exception\InvalidUriPatternException('the URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" contains succesive Dynamic Route Parts, which is not allowed.', 1218446975);
                 }
                 if (isset($this->routePartsConfiguration[$routePartName]['handler'])) {
                     $routePart = $this->objectManager->getObject($this->routePartsConfiguration[$routePartName]['handler']);
                     if (!$routePart instanceof \F3\FLOW3\MVC\Web\Routing\DynamicRoutePartInterface) {
                         throw new \F3\FLOW3\MVC\Exception\InvalidRoutePartHandlerException('routePart handlers must implement "\\F3\\FLOW3\\MVC\\Web\\Routing\\DynamicRoutePartInterface" in route "' . $this->getName() . '"', 1218480972);
                     }
                 } else {
                     $routePart = $this->objectFactory->create('F3\\FLOW3\\MVC\\Web\\Routing\\DynamicRoutePart');
                 }
                 if (isset($this->defaults[$routePartName])) {
                     $routePart->setDefaultValue($this->defaults[$routePartName]);
                 }
                 break;
             case self::ROUTEPART_TYPE_STATIC:
                 $routePart = $this->objectFactory->create('F3\\FLOW3\\MVC\\Web\\Routing\\StaticRoutePart');
                 if ($lastRoutePart !== NULL && $lastRoutePart instanceof \F3\FLOW3\MVC\Web\Routing\DynamicRoutePartInterface) {
                     $lastRoutePart->setSplitString($routePartName);
                 }
         }
         $routePart->setName($routePartName);
         $routePart->setOptional($currentRoutePartIsOptional);
         if ($this->lowerCase) {
             $routePart->setLowerCase(TRUE);
         }
         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 \F3\FLOW3\MVC\Exception\InvalidUriPatternException('The URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" contains an unopened optional section.', 1234564495);
             }
             $currentRoutePartIsOptional = FALSE;
         }
         $lastRoutePart = $routePart;
     }
     if ($currentRoutePartIsOptional) {
         throw new \F3\FLOW3\MVC\Exception\InvalidUriPatternException('The URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" contains an unterminated optional section.', 1234563922);
     }
     $this->isParsed = TRUE;
 }