/** * Move a settings path from "source" to "destination"; best to be used when package names change. * * @param string $sourcePath * @param string $destinationPath */ protected function moveSettingsPaths($sourcePath, $destinationPath) { $this->processConfiguration(ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, function (array &$configuration) use($sourcePath, $destinationPath) { $sourceConfigurationValue = Arrays::getValueByPath($configuration, $sourcePath); $destinationConfigurationValue = Arrays::getValueByPath($configuration, $destinationPath); if ($sourceConfigurationValue !== null) { // source exists, so we need to move source to destination. if ($destinationConfigurationValue !== null) { // target exists as well; we need to MERGE source and target. $destinationConfigurationValue = Arrays::arrayMergeRecursiveOverrule($sourceConfigurationValue, $destinationConfigurationValue); } else { // target does NOT exist; we directly set target = source $destinationConfigurationValue = $sourceConfigurationValue; } // set the config on the new path $configuration = Arrays::setValueByPath($configuration, $destinationPath, $destinationConfigurationValue); // Unset the old configuration $configuration = Arrays::unsetValueByPath($configuration, $sourcePath); // remove empty keys before our removed key (if it exists) $sourcePathExploded = explode('.', $sourcePath); for ($length = count($sourcePathExploded) - 1; $length > 0; $length--) { $temporaryPath = array_slice($sourcePathExploded, 0, $length); $valueAtPath = Arrays::getValueByPath($configuration, $temporaryPath); if (empty($valueAtPath)) { $configuration = Arrays::unsetValueByPath($configuration, $temporaryPath); } else { break; } } } }, true); }
/** * Checks whether $routeValues can be resolved to a corresponding uri. * If all Route Parts can resolve one or more of the $routeValues, TRUE is * returned and $this->matchingURI contains the generated URI (excluding * protocol and host). * * @param array $routeValues An array containing key/value pairs to be resolved to uri segments * @return boolean TRUE if this Route corresponds to the given $routeValues, otherwise FALSE * @throws InvalidRoutePartValueException */ public function resolves(array $routeValues) { $this->resolvedUriPath = null; if ($this->uriPattern === null) { return false; } if (!$this->isParsed) { $this->parse(); } $resolvedUriPath = ''; $remainingDefaults = $this->defaults; $requireOptionalRouteParts = false; $matchingOptionalUriPortion = ''; /** @var $routePart RoutePartInterface */ foreach ($this->routeParts as $routePart) { if (!$routePart->resolve($routeValues)) { if (!$routePart->hasDefaultValue()) { return false; } } if ($routePart->getName() !== null) { $remainingDefaults = Arrays::unsetValueByPath($remainingDefaults, $routePart->getName()); } $routePartValue = null; if ($routePart->hasValue()) { $routePartValue = $routePart->getValue(); if (!is_string($routePartValue)) { throw new InvalidRoutePartValueException('RoutePart::getValue() must return a string after calling RoutePart::resolve(), got ' . (is_object($routePartValue) ? get_class($routePartValue) : gettype($routePartValue)) . ' for RoutePart "' . get_class($routePart) . '" in Route "' . $this->getName() . '".'); } } $routePartDefaultValue = $routePart->getDefaultValue(); if ($routePartDefaultValue !== null && !is_string($routePartDefaultValue)) { throw new InvalidRoutePartValueException('RoutePart::getDefaultValue() must return a string, got ' . (is_object($routePartDefaultValue) ? get_class($routePartDefaultValue) : gettype($routePartDefaultValue)) . ' for RoutePart "' . get_class($routePart) . '" in Route "' . $this->getName() . '".'); } if (!$routePart->isOptional()) { $resolvedUriPath .= $routePart->hasValue() ? $routePartValue : $routePartDefaultValue; $requireOptionalRouteParts = false; continue; } if ($routePart->hasValue() && strtolower($routePartValue) !== strtolower($routePartDefaultValue)) { $matchingOptionalUriPortion .= $routePartValue; $requireOptionalRouteParts = true; } else { $matchingOptionalUriPortion .= $routePartDefaultValue; } if ($requireOptionalRouteParts) { $resolvedUriPath .= $matchingOptionalUriPortion; $matchingOptionalUriPortion = ''; } } if ($this->compareAndRemoveMatchingDefaultValues($remainingDefaults, $routeValues) !== true) { return false; } if (isset($routeValues['@format']) && $routeValues['@format'] === '') { unset($routeValues['@format']); } // add query string if (count($routeValues) > 0) { $routeValues = Arrays::removeEmptyElementsRecursively($routeValues); $routeValues = $this->persistenceManager->convertObjectsToIdentityArrays($routeValues); if (!$this->appendExceedingArguments) { $internalArguments = $this->extractInternalArguments($routeValues); if ($routeValues !== []) { return false; } $routeValues = $internalArguments; } $queryString = http_build_query($routeValues, null, '&'); if ($queryString !== '') { $resolvedUriPath .= strpos($resolvedUriPath, '?') !== false ? '&' . $queryString : '?' . $queryString; } } $this->resolvedUriPath = $resolvedUriPath; return true; }
/** * Checks whether $routeValues contains elements which correspond to this Dynamic Route Part. * If a corresponding element is found in $routeValues, this element is removed from the array. * * @param array $routeValues An array with key/value pairs to be resolved by Dynamic Route Parts. * @return boolean TRUE if current Route Part could be resolved, otherwise FALSE */ public final function resolve(array &$routeValues) { $this->value = null; if ($this->name === null || $this->name === '') { return false; } $valueToResolve = $this->findValueToResolve($routeValues); if (!$this->resolveValue($valueToResolve)) { return false; } $routeValues = Arrays::unsetValueByPath($routeValues, $this->name); return true; }
/** * @test * @expectedException \InvalidArgumentException */ public function unsetValueByPathThrowsExceptionIfPathIsNoArrayOrString() { $array = ['Foo' => ['Bar' => ['Baz' => [2 => 'the value']]]]; Arrays::unsetValueByPath($array, null); }
/** * Merges specified arguments with arguments from request. * * If $this->request is no sub request, request arguments will only be merged if $this->addQueryString is set. * Otherwise all request arguments except for the ones prefixed with the current request argument namespace will * be merged. Additionally special arguments (PackageKey, SubpackageKey, ControllerName & Action) are merged. * * The argument provided through the $arguments parameter always overrule the request * arguments. * * The request hierarchy is structured as follows: * root (HTTP) > main (Action) > sub (Action) > sub sub (Action) * * @param array $arguments * @return array */ protected function mergeArgumentsWithRequestArguments(array $arguments) { if ($this->request !== $this->request->getMainRequest()) { $subRequest = $this->request; while ($subRequest instanceof ActionRequest) { $requestArguments = (array) $subRequest->getArguments(); // Reset arguments for the request that is bound to this UriBuilder instance if ($subRequest === $this->request) { if ($this->addQueryString === false) { $requestArguments = []; } else { foreach ($this->argumentsToBeExcludedFromQueryString as $argumentToBeExcluded) { unset($requestArguments[$argumentToBeExcluded]); } } } else { // Remove all arguments of the current sub request if it's namespaced if ($this->request->getArgumentNamespace() !== '') { $requestNamespace = $this->getRequestNamespacePath($this->request); if ($this->addQueryString === false) { $requestArguments = Arrays::unsetValueByPath($requestArguments, $requestNamespace); } else { foreach ($this->argumentsToBeExcludedFromQueryString as $argumentToBeExcluded) { $requestArguments = Arrays::unsetValueByPath($requestArguments, $requestNamespace . '.' . $argumentToBeExcluded); } } } } // Merge special arguments (package, subpackage, controller & action) from main request $requestPackageKey = $subRequest->getControllerPackageKey(); if (!empty($requestPackageKey)) { $requestArguments['@package'] = $requestPackageKey; } $requestSubpackageKey = $subRequest->getControllerSubpackageKey(); if (!empty($requestSubpackageKey)) { $requestArguments['@subpackage'] = $requestSubpackageKey; } $requestControllerName = $subRequest->getControllerName(); if (!empty($requestControllerName)) { $requestArguments['@controller'] = $requestControllerName; } $requestActionName = $subRequest->getControllerActionName(); if (!empty($requestActionName)) { $requestArguments['@action'] = $requestActionName; } if (count($requestArguments) > 0) { $requestArguments = $this->addNamespaceToArguments($requestArguments, $subRequest); $arguments = Arrays::arrayMergeRecursiveOverrule($requestArguments, $arguments); } $subRequest = $subRequest->getParentRequest(); } } elseif ($this->addQueryString === true) { $requestArguments = $this->request->getArguments(); foreach ($this->argumentsToBeExcludedFromQueryString as $argumentToBeExcluded) { unset($requestArguments[$argumentToBeExcluded]); } if ($requestArguments !== []) { $arguments = Arrays::arrayMergeRecursiveOverrule($requestArguments, $arguments); } } return $arguments; }