diff --git a/src/BaseConfigRegistry.php b/src/BaseConfigRegistry.php index 42e742f5..499c327a 100644 --- a/src/BaseConfigRegistry.php +++ b/src/BaseConfigRegistry.php @@ -89,20 +89,27 @@ public function getEnvironment() private function addParentFilter(ModelIdInterface $idParent, ConfigInterface $config): ConfigInterface { $environment = $this->getEnvironment(); - $definition = $environment->getDataDefinition(); + assert($environment instanceof EnvironmentInterface); + + $definition = $environment->getDataDefinition(); if (null === $definition) { throw new DcGeneralRuntimeException('Data definition not set.'); } $basicDefinition = $definition->getBasicDefinition(); - $providerName = $basicDefinition->getDataProvider(); + $providerName = (string) $basicDefinition->getDataProvider(); $parentProviderName = $idParent->getDataProviderName(); $parentProvider = $environment->getDataProvider($parentProviderName); if ($basicDefinition->getParentDataProvider() !== $parentProviderName) { - throw new DcGeneralRuntimeException( - 'Unexpected parent provider ' . $parentProviderName . - ' (expected ' . ((string) $basicDefinition->getParentDataProvider()) . ')' - ); + // Could be a tree parent then. + if ($basicDefinition->getDataProvider() !== $parentProviderName) { + throw new DcGeneralRuntimeException( + 'Unexpected parent provider ' . $parentProviderName . + ' (expected ' . ((string) $basicDefinition->getParentDataProvider()) . ')' + ); + } + $parentProviderName = $providerName; + $parentProvider = $environment->getDataProvider($parentProviderName); } if ($parentProvider) { @@ -115,7 +122,7 @@ private function addParentFilter(ModelIdInterface $idParent, ConfigInterface $co $condition = $definition->getModelRelationshipDefinition()->getChildCondition( $parentProviderName, - (string) $providerName + $providerName ); if ($condition) { diff --git a/src/Contao/Dca/Builder/Legacy/ExtendedLegacyDcaDataDefinitionBuilder.php b/src/Contao/Dca/Builder/Legacy/ExtendedLegacyDcaDataDefinitionBuilder.php index e1736f64..d68e1a63 100644 --- a/src/Contao/Dca/Builder/Legacy/ExtendedLegacyDcaDataDefinitionBuilder.php +++ b/src/Contao/Dca/Builder/Legacy/ExtendedLegacyDcaDataDefinitionBuilder.php @@ -285,12 +285,11 @@ protected function parseDataProvider(ContainerInterface $container) } // First check if we are using the "new" notation used in DcGeneral 0.9. - if (!\is_array($this->getFromDca('dca_config/data_provider'))) { + $dataProvidersDca = $this->getFromDca('dca_config/data_provider'); + if (!\is_array($dataProvidersDca)) { return; } - $dataProvidersDca = $this->getFromDca('dca_config/data_provider'); - foreach ($dataProvidersDca as $dataProviderDcaName => $dataProviderDca) { $providerInformation = $this->parseSingleDataProvider( $container, @@ -326,6 +325,7 @@ protected function parseDataProvider(ContainerInterface $container) break; default: + $baseInitializationData['name'] = $providerInformation->getName(); } $providerInformation->setInitializationData( diff --git a/src/Contao/Dca/Populator/ParentDefinitionPopulator.php b/src/Contao/Dca/Populator/ParentDefinitionPopulator.php index c51866f1..af1689bd 100644 --- a/src/Contao/Dca/Populator/ParentDefinitionPopulator.php +++ b/src/Contao/Dca/Populator/ParentDefinitionPopulator.php @@ -55,6 +55,12 @@ public function populateController(EnvironmentInterface $environment) return; } + if ($parentDataProvider === $definition->getName()) { + $environment->setParentDataDefinition($definition); + + return; + } + if (null === $dispatcher = $environment->getEventDispatcher()) { throw new LogicException('No event dispatcher given'); } diff --git a/src/Contao/View/Contao2BackendView/ActionHandler/PasteHandler.php b/src/Contao/View/Contao2BackendView/ActionHandler/PasteHandler.php index 62141f14..57c5f7ce 100644 --- a/src/Contao/View/Contao2BackendView/ActionHandler/PasteHandler.php +++ b/src/Contao/View/Contao2BackendView/ActionHandler/PasteHandler.php @@ -3,7 +3,7 @@ /** * This file is part of contao-community-alliance/dc-general. * - * (c) 2013-2023 Contao Community Alliance. + * (c) 2013-2024 Contao Community Alliance. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,7 +15,7 @@ * @author Sven Baumann * @author David Molineus * @author Ingolf Steinhardt - * @copyright 2013-2023 Contao Community Alliance. + * @copyright 2013-2024 Contao Community Alliance. * @license https://github.com/contao-community-alliance/dc-general/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -144,7 +144,7 @@ protected function process(EnvironmentInterface $environment) return null; } - ViewHelpers::redirectHome($environment); + ViewHelpers::redirectCleanHome($environment, ['source', 'after', 'into']); return null; } diff --git a/src/Contao/View/Contao2BackendView/ActionHandler/SelectHandler.php b/src/Contao/View/Contao2BackendView/ActionHandler/SelectHandler.php index 1330216e..6db5632e 100644 --- a/src/Contao/View/Contao2BackendView/ActionHandler/SelectHandler.php +++ b/src/Contao/View/Contao2BackendView/ActionHandler/SelectHandler.php @@ -390,7 +390,7 @@ private function handleCopyAllAction(EnvironmentInterface $environment, Action $ foreach ($this->getModelIds($environment, $action, $this->getSubmitAction($environment)) as $modelId) { $inputProvider->setParameter('source', $modelId->getSerialized()); - $this->callAction($environment, 'copy'); + $this->callAction($environment, 'deepcopy'); $inputProvider->unsetParameter('source'); } diff --git a/src/Contao/View/Contao2BackendView/ButtonRenderer.php b/src/Contao/View/Contao2BackendView/ButtonRenderer.php index 962486d1..61f3f8aa 100644 --- a/src/Contao/View/Contao2BackendView/ButtonRenderer.php +++ b/src/Contao/View/Contao2BackendView/ButtonRenderer.php @@ -469,8 +469,9 @@ private function calculateParameters(CommandInterface $command, string $serializ } if (($command instanceof CutCommandInterface) || ($command instanceof CopyCommandInterface)) { // Cut & copy need some special information. - $parameters = []; - $parameters['act'] = $command->getName(); + if (!\array_key_exists('act', $parameters)) { + $parameters['act'] = $command->getName(); + } $inputProvider = $this->environment->getInputProvider(); assert($inputProvider instanceof InputProviderInterface); diff --git a/src/Contao/View/Contao2BackendView/Controller/ClipboardController.php b/src/Contao/View/Contao2BackendView/Controller/ClipboardController.php index ef67612e..6ea014fd 100644 --- a/src/Contao/View/Contao2BackendView/Controller/ClipboardController.php +++ b/src/Contao/View/Contao2BackendView/Controller/ClipboardController.php @@ -186,7 +186,7 @@ private function checkPermission(ActionEvent $event) * * @return void */ - private function clearClipboard(ActionEvent $event, $redirect = true) + private function clearClipboard(ActionEvent $event, bool $redirect = true): void { $environment = $event->getEnvironment(); diff --git a/src/Contao/View/Contao2BackendView/TreeView.php b/src/Contao/View/Contao2BackendView/TreeView.php index 6e8b39bf..a2f3e584 100644 --- a/src/Contao/View/Contao2BackendView/TreeView.php +++ b/src/Contao/View/Contao2BackendView/TreeView.php @@ -208,7 +208,7 @@ private function handleNodeStateChanges() $this->toggleModel($providerName, $modelId); } - ViewHelpers::redirectHome($environment); + ViewHelpers::redirectCleanHome($environment, ['ptg', 'provider']); } } diff --git a/src/Contao/View/Contao2BackendView/ViewHelpers.php b/src/Contao/View/Contao2BackendView/ViewHelpers.php index efeaf9e0..fba7c081 100644 --- a/src/Contao/View/Contao2BackendView/ViewHelpers.php +++ b/src/Contao/View/Contao2BackendView/ViewHelpers.php @@ -259,9 +259,56 @@ public static function redirectHome(EnvironmentInterface $environment): never $request = self::getRequest(); $routeName = $request->attributes->get('_route'); if ($routeName !== 'contao_backend') { - self::determineNewStyleRedirect($routeName, $request, $environment); + self::determineNewStyleRedirect($routeName, $request, $environment, []); } + self::determineLegacyRedirect($environment, $input); + } + + /** @param list $cleanNames */ + public static function redirectCleanHome(EnvironmentInterface $environment, array $cleanNames): never + { + $input = $environment->getInputProvider(); + assert($input instanceof InputProviderInterface); + + $request = self::getRequest(); + $routeName = $request->attributes->get('_route'); + if ($routeName !== 'contao_backend') { + self::determineNewStyleRedirect($routeName, $request, $environment, $cleanNames); + } + self::determineLegacyRedirect($environment, $input); + } + /** @param list $cleanNames */ + private static function determineNewStyleRedirect( + string $routeName, + Request $request, + EnvironmentInterface $environment, + array $cleanNames + ): never { + $routeGenerator = System::getContainer()->get('router'); + assert($routeGenerator instanceof UrlGeneratorInterface); + $parameters = $request->query->all(); + foreach ($cleanNames as $key) { + unset($parameters[$key]); + } + if ($routeName === $request->attributes->get('_route')) { + foreach ($request->attributes->get('_route_params') ?? [] as $key => $value) { + if ('_' === $key[0] || \in_array($key, $cleanNames, true)) { + continue; + } + $parameters[$key] = $value; + } + } + unset($parameters['act']); + $routeBase = $routeGenerator->generate($routeName, $parameters); + + self::dispatchRedirect($environment, new RedirectEvent($routeBase)); + } + + private static function determineLegacyRedirect( + EnvironmentInterface $environment, + InputProviderInterface $input, + ): never { if ($input->hasParameter('table')) { if ($input->hasParameter('pid')) { $event = new RedirectEvent( @@ -288,28 +335,6 @@ public static function redirectHome(EnvironmentInterface $environment): never self::dispatchRedirect($environment, $event); } - private static function determineNewStyleRedirect( - string $routeName, - Request $request, - EnvironmentInterface $environment - ): never { - $routeGenerator = System::getContainer()->get('router'); - assert($routeGenerator instanceof UrlGeneratorInterface); - $parameters = $request->query->all(); - if ($routeName === $request->attributes->get('_route')) { - foreach ($request->attributes->get('_route_params') ?? [] as $key => $value) { - if ('_' === $key[0]) { - continue; - } - $parameters[$key] = $value; - } - } - unset($parameters['act']); - $routeBase = $routeGenerator->generate($routeName, $parameters); - - self::dispatchRedirect($environment, new RedirectEvent($routeBase)); - } - private static function getRequest(): Request { $requestStack = System::getContainer()->get('request_stack'); diff --git a/src/Controller/DefaultController.php b/src/Controller/DefaultController.php index a9e9d822..60c95f94 100644 --- a/src/Controller/DefaultController.php +++ b/src/Controller/DefaultController.php @@ -732,7 +732,7 @@ private function doActions( // Now apply sorting and persist all models. $models = $this->sortAndPersistModels($actions, $after, $into, $parentModelId, $items); - // At least, go ahead with the deep copy. + // At last, go ahead with the deep copy. $this->doDeepCopy($deepCopyList); return $models; @@ -1112,14 +1112,14 @@ protected function doDeepCopy(array $deepCopyList) $groupAndSortingCollection = $listingConfig->getGroupAndSortingDefinition(); $groupAndSorting = $groupAndSortingCollection->getDefault(); - // ***** fetch the children + // ***** fetch the children. $filter = $childCondition->getFilter($origin); // apply parent-child condition $config = $destinationDataProvider->getEmptyConfig(); $config->setFilter($filter); - // apply sorting + // Apply sorting. $sorting = []; foreach ($groupAndSorting as $information) { /** @var GroupAndSortingInformationInterface $information */ @@ -1127,13 +1127,13 @@ protected function doDeepCopy(array $deepCopyList) } $config->setSorting($sorting); - // receive children + // Receive children. $children = $destinationDataProvider->fetchAll($config); - // ***** do the deep copy + // ***** do the deep copy. $actions = []; - // build the copy actions + // Build the copy actions. foreach ($children as $childModel) { if (!($childModel instanceof ModelInterface)) { continue; @@ -1147,8 +1147,8 @@ protected function doDeepCopy(array $deepCopyList) ]; } - // do the deep copy - $childrenModels = $destinationController->doActions($actions, null, null, $parentId); + // Do the deep copy. + $childrenModels = $destinationController->doActions($actions, null, $parentId, null); // ensure parent-child condition foreach ($childrenModels as $childrenModel) { diff --git a/src/Controller/ModelCollector.php b/src/Controller/ModelCollector.php index 99c4b25a..58719ffd 100644 --- a/src/Controller/ModelCollector.php +++ b/src/Controller/ModelCollector.php @@ -3,7 +3,7 @@ /** * This file is part of contao-community-alliance/dc-general. * - * (c) 2013-2023 Contao Community Alliance. + * (c) 2013-2024 Contao Community Alliance. * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,7 +16,7 @@ * @author Ingolf Steinhardt * @author David Molineus * @author Stefan Heimes - * @copyright 2013-2023 Contao Community Alliance. + * @copyright 2013-2024 Contao Community Alliance. * @license https://github.com/contao-community-alliance/dc-general/blob/master/LICENSE LGPL-3.0-or-later * @filesource */ @@ -160,6 +160,8 @@ public function __construct(EnvironmentInterface $environment) * * @return ModelInterface|null * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * * @throws \InvalidArgumentException When the model id is invalid. */ public function getModel($modelId, $providerName = null) @@ -185,34 +187,34 @@ public function getModel($modelId, $providerName = null) assert($dataProvider instanceof DataProviderInterface); $config = $dataProvider->getEmptyConfig(); + $config->setId($modelId->getId()); if ($definition->getName() === $modelId->getDataProviderName()) { $propertyDefinition = $definition->getPropertiesDefinition(); } elseif ($parentDefinition && $parentDefinition->getName() === $modelId->getDataProviderName()) { $propertyDefinition = $parentDefinition->getPropertiesDefinition(); } else { - throw new \InvalidArgumentException('Invalid provider name ' . $modelId->getDataProviderName()); + $propertyDefinition = null; } + if (null !== $propertyDefinition) { + $properties = []; + // Filter real properties from the property definition. + foreach ($propertyDefinition->getPropertyNames() as $propertyName) { + if ($dataProvider->fieldExists($propertyName)) { + $properties[] = $propertyName; + continue; + } - $properties = []; - - // Filter real properties from the property definition. - foreach ($propertyDefinition->getPropertyNames() as $propertyName) { - if ($dataProvider->fieldExists($propertyName)) { - $properties[] = $propertyName; - - continue; + // @codingStandardsIgnoreStart + @\trigger_error( + 'Only real property is allowed in the property definition.' . + 'This will no longer be supported in the future.', + E_USER_DEPRECATED + ); + // @codingStandardsIgnoreEnd } - - // @codingStandardsIgnoreStart - @\trigger_error( - 'Only real property is allowed in the property definition.' . - 'This will no longer be supported in the future.', - E_USER_DEPRECATED - ); - // @codingStandardsIgnoreEnd + $config->setFields($properties); } - $config->setId($modelId->getId())->setFields($properties); return $dataProvider->fetch($config); }