From 6396f8a82e91a25fe69be45d91baf9003683d504 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Fri, 20 Jun 2025 12:37:22 +0100 Subject: [PATCH 1/4] IBX-10186 Port forward patch --- src/bundle/Controller/LocationController.php | 2 +- .../Configuration/Parser/SubtreeOperations.php | 8 ++++++++ .../config/ezplatform_default_settings.yaml | 1 + .../admin/content/tab/locations/tab.html.twig | 2 +- .../TrashLocationOptionProvider/HasChildren.php | 17 ++++++++++++++--- src/lib/Specification/Location/HasChildren.php | 2 +- .../Location/IsWithinCopySubtreeLimit.php | 2 +- src/lib/Tab/LocationView/LocationsTab.php | 6 ++++++ .../Subitems/ContentViewParameterSupplier.php | 14 ++++++++++++-- src/lib/UI/Value/ValueFactory.php | 2 ++ 10 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/bundle/Controller/LocationController.php b/src/bundle/Controller/LocationController.php index 1ad53bd9f1..7ca3faf241 100644 --- a/src/bundle/Controller/LocationController.php +++ b/src/bundle/Controller/LocationController.php @@ -302,7 +302,7 @@ public function swapAction(Request $request): Response $currentLocation = $data->getCurrentLocation(); $newLocation = $data->getNewLocation(); - $childCount = $this->locationService->getLocationChildCount($currentLocation); + $childCount = $this->locationService->getLocationChildCount($currentLocation, 1); $contentType = $newLocation->getContent()->getContentType(); if (!$contentType->isContainer && $childCount) { diff --git a/src/bundle/DependencyInjection/Configuration/Parser/SubtreeOperations.php b/src/bundle/DependencyInjection/Configuration/Parser/SubtreeOperations.php index 066539d54d..33597d6a4d 100644 --- a/src/bundle/DependencyInjection/Configuration/Parser/SubtreeOperations.php +++ b/src/bundle/DependencyInjection/Configuration/Parser/SubtreeOperations.php @@ -54,6 +54,14 @@ public function addSemanticConfig(NodeBuilder $nodeBuilder): void ->end() ->end() ->end() + ->arrayNode('query_subtree') + ->children() + ->integerNode('limit') + ->info('Limit the total count of items queried for when calculating the the number of direct children a node has. -1 for no limit. Default is 500 for performance reasons.') + ->defaultValue(500) + ->isRequired() + ->end() + ->end() ->end() ->end(); } diff --git a/src/bundle/Resources/config/ezplatform_default_settings.yaml b/src/bundle/Resources/config/ezplatform_default_settings.yaml index 7c6cbb3174..1c634d0acb 100644 --- a/src/bundle/Resources/config/ezplatform_default_settings.yaml +++ b/src/bundle/Resources/config/ezplatform_default_settings.yaml @@ -42,6 +42,7 @@ parameters: # Subtree Operations ibexa.site_access.config.admin_group.subtree_operations.copy_subtree.limit: 100 + ibexa.site_access.config.admin_group.subtree_operations.query_subtree.limit: 500 # Notifications ibexa.site_access.config.admin_group.notification_count.interval: 30000 diff --git a/src/bundle/Resources/views/themes/admin/content/tab/locations/tab.html.twig b/src/bundle/Resources/views/themes/admin/content/tab/locations/tab.html.twig index 76f815b075..842425dee1 100644 --- a/src/bundle/Resources/views/themes/admin/content/tab/locations/tab.html.twig +++ b/src/bundle/Resources/views/themes/admin/content/tab/locations/tab.html.twig @@ -82,7 +82,7 @@ }]) %} {% set body_row_cols = body_row_cols|merge([ - { content: location.childCount }, + { content: (location.childCount > sub_item_query_limit) ? location.childCount ~ '+' : location.childCount }, ]) %} {% set body_rows = body_rows|merge([{ cols: body_row_cols }]) %} diff --git a/src/lib/Form/TrashLocationOptionProvider/HasChildren.php b/src/lib/Form/TrashLocationOptionProvider/HasChildren.php index fee9fe66d2..1d7e57871f 100644 --- a/src/lib/Form/TrashLocationOptionProvider/HasChildren.php +++ b/src/lib/Form/TrashLocationOptionProvider/HasChildren.php @@ -11,6 +11,7 @@ use Ibexa\AdminUi\Specification\Location\HasChildren as HasChildrenSpec; use Ibexa\Contracts\Core\Repository\LocationService; use Ibexa\Contracts\Core\Repository\Values\Content\Location; +use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormInterface; use Symfony\Contracts\Translation\TranslatorInterface; @@ -22,11 +23,15 @@ final class HasChildren implements TrashLocationOptionProvider /** @var \Symfony\Contracts\Translation\TranslatorInterface */ private $translator; + + /** @var \Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface */ + private $configResolver; - public function __construct(LocationService $locationService, TranslatorInterface $translator) + public function __construct(LocationService $locationService, TranslatorInterface $translator, ConfigResolverInterface $configResolver) { $this->locationService = $locationService; $this->translator = $translator; + $this->configResolver = $configResolver; } public function supports(Location $location): bool @@ -36,10 +41,16 @@ public function supports(Location $location): bool public function addOptions(FormInterface $form, Location $location): void { - $childCount = $this->locationService->getLocationChildCount($location); + $limit = $this->configResolver->getParameter('subtree_operations.query_subtree.limit'); + + $useLimit = $limit > 0; + $childCount = $this->locationService->getLocationChildCount($location, $useLimit ? $limit + 1 : null); + $translatorParameters = [ - '%children_count%' => $childCount, + '%children_count%' => ($useLimit && $childCount >= $limit) ? + sprintf('%d+', $limit) : + $childCount,, '%content%' => $location->getContent()->getName(), ]; diff --git a/src/lib/Specification/Location/HasChildren.php b/src/lib/Specification/Location/HasChildren.php index 227a583e3b..e23bbc614b 100644 --- a/src/lib/Specification/Location/HasChildren.php +++ b/src/lib/Specification/Location/HasChildren.php @@ -31,7 +31,7 @@ public function __construct(LocationService $locationService) */ public function isSatisfiedBy($item): bool { - $childCount = $this->locationService->getLocationChildCount($item); + $childCount = $this->locationService->getLocationChildCount($item, 1); return 0 < $childCount; } diff --git a/src/lib/Specification/Location/IsWithinCopySubtreeLimit.php b/src/lib/Specification/Location/IsWithinCopySubtreeLimit.php index 2a90c52142..7b4b546207 100644 --- a/src/lib/Specification/Location/IsWithinCopySubtreeLimit.php +++ b/src/lib/Specification/Location/IsWithinCopySubtreeLimit.php @@ -44,7 +44,7 @@ public function isSatisfiedBy($item): bool return false; } - return $this->copyLimit >= $this->locationService->getSubtreeSize($item); + return $this->copyLimit >= $this->locationService->getSubtreeSize($item, $this->copyLimit + 1); } private function isContainer(Location $location): bool diff --git a/src/lib/Tab/LocationView/LocationsTab.php b/src/lib/Tab/LocationView/LocationsTab.php index 43f53aeb1e..48e2e02fc7 100644 --- a/src/lib/Tab/LocationView/LocationsTab.php +++ b/src/lib/Tab/LocationView/LocationsTab.php @@ -206,12 +206,18 @@ public function getTemplateParameters(array $contextParameters = []): array ); } + $subItemQueryLimit = $this->configResolver->getParameter('subtree_operations.query_subtree.limit'); + if ($subItemQueryLimit <= 0) { + $subItemQueryLimit = null; + } + $viewParameters = [ 'pager' => $pagination, 'pager_options' => [ 'pageParameter' => sprintf('[%s]', self::PAGINATION_PARAM_NAME), ], 'locations' => $locations, + 'sub_item_query_limit' => $subItemQueryLimit, 'form_content_location_add' => $formLocationAdd->createView(), 'form_content_location_remove' => $formLocationRemove->createView(), 'form_content_location_swap' => $formLocationSwap->createView(), diff --git a/src/lib/UI/Module/Subitems/ContentViewParameterSupplier.php b/src/lib/UI/Module/Subitems/ContentViewParameterSupplier.php index f57b8819da..50e91682f0 100644 --- a/src/lib/UI/Module/Subitems/ContentViewParameterSupplier.php +++ b/src/lib/UI/Module/Subitems/ContentViewParameterSupplier.php @@ -20,6 +20,7 @@ use Ibexa\Contracts\Core\Repository\Values\Content\Content; use Ibexa\Contracts\Core\Repository\Values\Content\Location; use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType; +use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; use Ibexa\Contracts\Rest\Output\Visitor; use Ibexa\Core\MVC\Symfony\View\ContentView; use Ibexa\Core\Query\QueryFactoryInterface; @@ -69,6 +70,8 @@ class ContentViewParameterSupplier private SearchService $searchService; + private ConfigResolverInterface $configResolver; + public function __construct( Visitor $outputVisitor, JsonOutputGenerator $outputGenerator, @@ -81,7 +84,8 @@ public function __construct( ContentTypeMappings $contentTypeMappings, UserSettingService $userSettingService, QueryFactoryInterface $queryFactory, - SearchService $searchService + SearchService $searchService, + ConfigResolverInterface $configResolver ) { $this->outputVisitor = $outputVisitor; $this->outputGenerator = $outputGenerator; @@ -95,6 +99,7 @@ public function __construct( $this->userSettingService = $userSettingService; $this->queryFactory = $queryFactory; $this->searchService = $searchService; + $this->configResolver = $configResolver; } /** @@ -185,7 +190,12 @@ private function createRestLocation(Location $location): RestLocation { return new RestLocation( $location, - $this->locationService->getLocationChildCount($location) + $this->locationService->getLocationChildCount( + $location, + // For the sub items module we only ever use the count to determine if there are children (0 or 1+), + // hence setting a limit of 1 is sufficient here. + 1 + ) ); } diff --git a/src/lib/UI/Value/ValueFactory.php b/src/lib/UI/Value/ValueFactory.php index 995f889b4c..60ade28a92 100644 --- a/src/lib/UI/Value/ValueFactory.php +++ b/src/lib/UI/Value/ValueFactory.php @@ -74,6 +74,8 @@ class ValueFactory /** @var \Ibexa\Core\Repository\LocationResolver\LocationResolver */ protected $locationResolver; + /** @var \eZ\Publish\Core\MVC\ConfigResolverInterface */ + /** * @param \Ibexa\Contracts\Core\Repository\UserService $userService * @param \Ibexa\Contracts\Core\Repository\LanguageService $languageService From 6f5f10931dd326144b5e12fa37bb3ee6115b4556 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Fri, 20 Jun 2025 14:20:58 +0100 Subject: [PATCH 2/4] IBX-10186 Remove problematic double comma --- src/lib/Form/TrashLocationOptionProvider/HasChildren.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Form/TrashLocationOptionProvider/HasChildren.php b/src/lib/Form/TrashLocationOptionProvider/HasChildren.php index 1d7e57871f..cacd363c33 100644 --- a/src/lib/Form/TrashLocationOptionProvider/HasChildren.php +++ b/src/lib/Form/TrashLocationOptionProvider/HasChildren.php @@ -50,7 +50,7 @@ public function addOptions(FormInterface $form, Location $location): void $translatorParameters = [ '%children_count%' => ($useLimit && $childCount >= $limit) ? sprintf('%d+', $limit) : - $childCount,, + $childCount, '%content%' => $location->getContent()->getName(), ]; From 8a990307064aae39ec77939d97ad39e78070fc3e Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Fri, 20 Jun 2025 14:36:43 +0100 Subject: [PATCH 3/4] IBX-10186 Fix value factory constraints --- src/lib/UI/Value/ValueFactory.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/lib/UI/Value/ValueFactory.php b/src/lib/UI/Value/ValueFactory.php index 60ade28a92..59026d1133 100644 --- a/src/lib/UI/Value/ValueFactory.php +++ b/src/lib/UI/Value/ValueFactory.php @@ -36,6 +36,7 @@ use Ibexa\Contracts\Core\Repository\Values\ObjectState\ObjectStateGroup; use Ibexa\Contracts\Core\Repository\Values\User\Policy; use Ibexa\Contracts\Core\Repository\Values\User\RoleAssignment; +use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; use Ibexa\Core\MVC\Symfony\Locale\UserLanguagePreferenceProviderInterface; use Ibexa\Core\Repository\LocationResolver\LocationResolver; @@ -74,7 +75,8 @@ class ValueFactory /** @var \Ibexa\Core\Repository\LocationResolver\LocationResolver */ protected $locationResolver; - /** @var \eZ\Publish\Core\MVC\ConfigResolverInterface */ + /** @var \Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface */ + protected $configResolver; /** * @param \Ibexa\Contracts\Core\Repository\UserService $userService @@ -88,6 +90,7 @@ class ValueFactory * @param \Ibexa\AdminUi\UI\Dataset\DatasetFactory $datasetFactory * @param \Ibexa\Core\MVC\Symfony\Locale\UserLanguagePreferenceProviderInterface $userLanguagePreferenceProvider * @param \Ibexa\Core\Repository\LocationResolver\LocationResolver $locationResolver + * @param \Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface $configResolver */ public function __construct( UserService $userService, @@ -100,7 +103,8 @@ public function __construct( PathService $pathService, DatasetFactory $datasetFactory, UserLanguagePreferenceProviderInterface $userLanguagePreferenceProvider, - LocationResolver $locationResolver + LocationResolver $locationResolver, + ConfigResolverInterface $configResolver ) { $this->userService = $userService; $this->languageService = $languageService; @@ -113,6 +117,7 @@ public function __construct( $this->datasetFactory = $datasetFactory; $this->userLanguagePreferenceProvider = $userLanguagePreferenceProvider; $this->locationResolver = $locationResolver; + $this->configResolver = $configResolver; } /** @@ -239,9 +244,11 @@ public function createLocation(Location $location): UIValue\Content\Location { $translations = $location->getContent()->getVersionInfo()->languageCodes; $target = (new Target\Version())->deleteTranslations($translations); + $limit = $this->configResolver->getParameter('subtree_operations.query_subtree.limit'); + $useLimit = $limit > 0; return new UIValue\Content\Location($location, [ - 'childCount' => $this->locationService->getLocationChildCount($location), + 'childCount' => $this->locationService->getLocationChildCount($location, $useLimit ? $limit + 1 : null), 'pathLocations' => $this->pathService->loadPathLocations($location), 'userCanManage' => $this->permissionResolver->canUser( 'content', From 196ccb2292802a396e62586e6194787a9df36f46 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Fri, 20 Jun 2025 15:13:07 +0100 Subject: [PATCH 4/4] IBX-10186 Run CS at tell github to stop being problematic --- .../views/themes/admin/content/tab/locations/tab.html.twig | 2 +- src/lib/Form/TrashLocationOptionProvider/HasChildren.php | 5 ++--- src/lib/UI/Module/Subitems/ContentViewParameterSupplier.php | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/bundle/Resources/views/themes/admin/content/tab/locations/tab.html.twig b/src/bundle/Resources/views/themes/admin/content/tab/locations/tab.html.twig index 842425dee1..efa580390a 100644 --- a/src/bundle/Resources/views/themes/admin/content/tab/locations/tab.html.twig +++ b/src/bundle/Resources/views/themes/admin/content/tab/locations/tab.html.twig @@ -82,7 +82,7 @@ }]) %} {% set body_row_cols = body_row_cols|merge([ - { content: (location.childCount > sub_item_query_limit) ? location.childCount ~ '+' : location.childCount }, + { content: (location.childCount > sub_item_query_limit) ? (location.childCount -1) ~ '+' : location.childCount }, ]) %} {% set body_rows = body_rows|merge([{ cols: body_row_cols }]) %} diff --git a/src/lib/Form/TrashLocationOptionProvider/HasChildren.php b/src/lib/Form/TrashLocationOptionProvider/HasChildren.php index cacd363c33..ab8f7cbd4d 100644 --- a/src/lib/Form/TrashLocationOptionProvider/HasChildren.php +++ b/src/lib/Form/TrashLocationOptionProvider/HasChildren.php @@ -23,8 +23,8 @@ final class HasChildren implements TrashLocationOptionProvider /** @var \Symfony\Contracts\Translation\TranslatorInterface */ private $translator; - - /** @var \Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface */ + + /** @var \Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface */ private $configResolver; public function __construct(LocationService $locationService, TranslatorInterface $translator, ConfigResolverInterface $configResolver) @@ -45,7 +45,6 @@ public function addOptions(FormInterface $form, Location $location): void $useLimit = $limit > 0; $childCount = $this->locationService->getLocationChildCount($location, $useLimit ? $limit + 1 : null); - $translatorParameters = [ '%children_count%' => ($useLimit && $childCount >= $limit) ? diff --git a/src/lib/UI/Module/Subitems/ContentViewParameterSupplier.php b/src/lib/UI/Module/Subitems/ContentViewParameterSupplier.php index 50e91682f0..a48d4285b4 100644 --- a/src/lib/UI/Module/Subitems/ContentViewParameterSupplier.php +++ b/src/lib/UI/Module/Subitems/ContentViewParameterSupplier.php @@ -192,8 +192,8 @@ private function createRestLocation(Location $location): RestLocation $location, $this->locationService->getLocationChildCount( $location, - // For the sub items module we only ever use the count to determine if there are children (0 or 1+), - // hence setting a limit of 1 is sufficient here. + // For the sub items module we only ever use the count to determine if there are children (0 or 1+), + // hence setting a limit of 1 is sufficient here. 1 ) );