diff --git a/src/lib/Menu/ContentRightSidebarBuilder.php b/src/lib/Menu/ContentRightSidebarBuilder.php index d408db5b47..0c94e59a08 100644 --- a/src/lib/Menu/ContentRightSidebarBuilder.php +++ b/src/lib/Menu/ContentRightSidebarBuilder.php @@ -425,16 +425,23 @@ private function canCopy(bool $hasCreatePermission): bool private function canCopySubtree(Location $location, bool $hasCreatePermission): bool { - $copyLimit = $this->configResolver->getParameter( - 'subtree_operations.copy_subtree.limit' - ); + if (!$hasCreatePermission) { + return false; + } - $canCopySubtree = (new IsWithinCopySubtreeLimit( - $copyLimit, + $isWithinCopySubtreeLimit = new IsWithinCopySubtreeLimit( + $this->getCopySubtreeLimit(), $this->locationService - ))->and((new IsRoot())->not())->isSatisfiedBy($location); + ); - return $canCopySubtree && $hasCreatePermission; + return (new IsRoot())->not()->and($isWithinCopySubtreeLimit)->isSatisfiedBy($location); + } + + private function getCopySubtreeLimit(): int + { + return $this->configResolver->getParameter( + 'subtree_operations.copy_subtree.limit' + ); } } diff --git a/src/lib/Specification/Location/IsWithinCopySubtreeLimit.php b/src/lib/Specification/Location/IsWithinCopySubtreeLimit.php index 9b94a1c592..2a90c52142 100644 --- a/src/lib/Specification/Location/IsWithinCopySubtreeLimit.php +++ b/src/lib/Specification/Location/IsWithinCopySubtreeLimit.php @@ -10,8 +10,7 @@ use Ibexa\AdminUi\Specification\AbstractSpecification; use Ibexa\Contracts\Core\Repository\LocationService; -use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion; -use Ibexa\Contracts\Core\Repository\Values\Filter\Filter; +use Ibexa\Contracts\Core\Repository\Values\Content\Location; /** * @internal @@ -34,10 +33,6 @@ public function __construct( /** * @param \Ibexa\Contracts\Core\Repository\Values\Content\Location $item - * - * @return bool - * - * @throws \Ibexa\Contracts\Core\Repository\Exceptions\BadStateException */ public function isSatisfiedBy($item): bool { @@ -45,13 +40,16 @@ public function isSatisfiedBy($item): bool return true; } - if ($this->copyLimit === 0) { + if ($this->copyLimit === 0 || !$this->isContainer($item)) { return false; } - $filter = new Filter(new Criterion\Subtree($item->pathString)); + return $this->copyLimit >= $this->locationService->getSubtreeSize($item); + } - return $this->copyLimit >= $this->locationService->count($filter); + private function isContainer(Location $location): bool + { + return $location->getContentInfo()->getContentType()->isContainer(); } } diff --git a/tests/lib/Validator/Constraint/LocationIsWithinCopySubtreeLimitValidatorTest.php b/tests/lib/Validator/Constraint/LocationIsWithinCopySubtreeLimitValidatorTest.php index 86212d6d8d..409071da3e 100644 --- a/tests/lib/Validator/Constraint/LocationIsWithinCopySubtreeLimitValidatorTest.php +++ b/tests/lib/Validator/Constraint/LocationIsWithinCopySubtreeLimitValidatorTest.php @@ -11,8 +11,11 @@ use Ibexa\AdminUi\Validator\Constraints\LocationIsWithinCopySubtreeLimit; use Ibexa\AdminUi\Validator\Constraints\LocationIsWithinCopySubtreeLimitValidator; use Ibexa\Contracts\Core\Repository\LocationService; +use Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo; use Ibexa\Contracts\Core\Repository\Values\Content\Location; +use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType; use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface; @@ -62,6 +65,8 @@ public function testValid(): void ->expects($this->never()) ->method('addViolation'); + $this->mockLocationContentContentTypeIsContainer($this->location); + $this->validator->validate($this->location, new LocationIsWithinCopySubtreeLimit()); } @@ -87,6 +92,16 @@ public function testInvalid(): void $this->validator->validate($this->location, new LocationIsWithinCopySubtreeLimit()); } + + private function mockLocationContentContentTypeIsContainer(MockObject $location): void + { + $contentType = $this->createMock(ContentType::class); + $contentType->method('isContainer')->willReturn(true); + $contentInfo = $this->createMock(ContentInfo::class); + $contentInfo->method('getContentType')->willReturn($contentType); + + $location->method('getContentInfo')->willReturn($contentInfo); + } } class_alias(LocationIsWithinCopySubtreeLimitValidatorTest::class, 'EzSystems\EzPlatformAdminUi\Tests\Validator\Constraint\LocationIsWithinCopySubtreeLimitValidatorTest');