Skip to content

Commit

Permalink
EZP-30746: Fixed respecting hidden Content when moving subtree
Browse files Browse the repository at this point in the history
For more details see https://issues.ibexa.co/browse/EZP-30746 and #310

* Fixed respecting hidden Content when moving subtree

* [Tests] Added test coverage for hidden Content in moved subtree

Co-authored-by: Vidar Langseid <vidarl@users.noreply.github.com>
  • Loading branch information
vidarl and vidarl authored Jun 15, 2022
1 parent 1ee2154 commit fabd714
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 16 deletions.
129 changes: 129 additions & 0 deletions eZ/Publish/API/Repository/Tests/LocationServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3238,6 +3238,135 @@ public function testMoveSubtreeUpdatesPathIdentificationString(): void
);
}

/**
* Test that is_visible is set correct for children when moving a location where a child is hidden by content (not by location).
*
* @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
*/
public function testMoveSubtreeKeepsContentHiddenOnChildrenAndParent(): void
{
$repository = $this->getRepository();

$mediaLocationId = $this->generateId('location', 43);

$locationService = $repository->getLocationService();
$contentService = $repository->getContentService();

$sourceFolderContent = $this->publishContentWithParentLocation('SourceFolder', $mediaLocationId); // media/SourceFolder
$subFolderContent1 = $this->publishContentWithParentLocation('subFolderContent1', $sourceFolderContent->contentInfo->mainLocationId);
$subFolderContent2 = $this->publishContentWithParentLocation('subFolderContent2', $sourceFolderContent->contentInfo->mainLocationId);
$targetFolderContent = $this->publishContentWithParentLocation('targetFolder', $mediaLocationId); // media/TargetFolder

$contentService->hideContent($subFolderContent1->contentInfo);

// Move media/SourceFolder to media/TargetFolder/
$locationService->moveSubtree(
$sourceFolderContent->contentInfo->getMainLocation(),
$targetFolderContent->contentInfo->getMainLocation()
);

$movedLocation = $locationService->loadLocation($sourceFolderContent->contentInfo->mainLocationId);
$newParentLocation = $locationService->loadLocation($targetFolderContent->contentInfo->mainLocationId);

// Assert Moved Location remains visible ( only child is hidden )
$this->assertPropertiesCorrect(
[
'hidden' => false,
'invisible' => false,
'depth' => $newParentLocation->depth + 1,
'parentLocationId' => $newParentLocation->id,
'pathString' => $newParentLocation->pathString . $this->parseId('location', $movedLocation->id) . '/',
],
$movedLocation
);
self::assertFalse($movedLocation->getContentInfo()->isHidden);

// Assert children of Moved location
$childrenLocations = [
$subFolderContent1->contentInfo->getMainLocation(),
$subFolderContent2->contentInfo->getMainLocation(),
];
foreach ($childrenLocations as $childLocation) {
$this->assertPropertiesCorrect(
[
'hidden' => $childLocation === $subFolderContent1->contentInfo->getMainLocation(), // Only SubFolderContent1 should be hidden,
'invisible' => $childLocation === $subFolderContent1->contentInfo->getMainLocation(), // Only SubFolderContent1 should be hidden
'depth' => $movedLocation->depth + 1,
'parentLocationId' => $movedLocation->id,
'pathString' => $movedLocation->pathString . $this->parseId('location', $childLocation->id) . '/',
],
$childLocation
);
self::assertEquals($childLocation === $subFolderContent1->contentInfo->getMainLocation(), $childLocation->getContentInfo()->isHidden);
}
}

/**
* Test that is_visible is set correct for children when moving a content which is hidden (location is not hidden).
*
* @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
*/
public function testMoveSubtreeKeepsContentHiddenOnChildren(): void
{
$repository = $this->getRepository();

$sourceLocationId = $this->createFolder(
[
'eng-GB' => 'SourceParentFolder',
],
2
)->getVersionInfo()->getContentInfo()->mainLocationId;

$locationService = $repository->getLocationService();
$contentService = $repository->getContentService();

$sourceFolderContent = $this->publishContentWithParentLocation('SourceFolder', $sourceLocationId); // media/SourceFolder
$subFolderContent1 = $this->publishContentWithParentLocation('subFolderContent1', $sourceFolderContent->contentInfo->mainLocationId);
$subFolderContent2 = $this->publishContentWithParentLocation('subFolderContent2', $sourceFolderContent->contentInfo->mainLocationId);
$targetFolderContent = $this->publishContentWithParentLocation('targetFolder', $sourceLocationId); // media/TargetFolder

$contentService->hideContent($sourceFolderContent->contentInfo);

// Move media/SourceFolder to media/TargetFolder/
$locationService->moveSubtree(
$sourceFolderContent->contentInfo->getMainLocation(),
$targetFolderContent->contentInfo->getMainLocation()
);

$movedLocation = $locationService->loadLocation($sourceFolderContent->contentInfo->mainLocationId);
$newParentLocation = $locationService->loadLocation($targetFolderContent->contentInfo->mainLocationId);

// Assert Moved Location
$this->assertPropertiesCorrect(
[
'hidden' => true,
'invisible' => true,
'depth' => $newParentLocation->depth + 1,
'parentLocationId' => $newParentLocation->id,
'pathString' => $newParentLocation->pathString . $this->parseId('location', $movedLocation->id) . '/',
],
$movedLocation
);

self::assertTrue($movedLocation->getContentInfo()->isHidden);

// Assert children of Moved location
$childLocations = [$subFolderContent1->contentInfo->getMainLocation(), $subFolderContent2->contentInfo->getMainLocation()];
foreach ($childLocations as $childLocation) {
$this->assertPropertiesCorrect(
[
'hidden' => false,
'invisible' => true,
'depth' => $movedLocation->depth + 1,
'parentLocationId' => $movedLocation->id,
'pathString' => $movedLocation->pathString . $this->parseId('location', $childLocation->id) . '/',
],
$childLocation
);
self::assertFalse($childLocation->getContentInfo()->isHidden);
}
}

/**
* Loads properties from all locations in the $location's subtree.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,14 @@ private function getSubtreeNodesData(string $pathString): array
return $statement->fetchAll();
}

/**
* @throws \Doctrine\DBAL\Exception
* @throws \Doctrine\DBAL\Driver\Exception
*/
public function moveSubtreeNodes(array $sourceNodeData, array $destinationNodeData): void
{
$fromPathString = $sourceNodeData['path_string'];
$contentObjectId = $sourceNodeData['contentobject_id'];

$rows = $this->getSubtreeNodesData($fromPathString);

Expand All @@ -304,7 +309,7 @@ public function moveSubtreeNodes(array $sourceNodeData, array $destinationNodeDa
array_slice(explode('/', $sourceNodeData['path_identification_string']), 0, -1)
);

$hiddenNodeIds = $this->getHiddenNodeIds($rows);
$hiddenNodeIds = $this->getHiddenNodeIds($contentObjectId);
foreach ($rows as $row) {
// Prefixing ensures correct replacement when old parent is root node
$newPathString = str_replace(
Expand Down Expand Up @@ -338,28 +343,41 @@ public function moveSubtreeNodes(array $sourceNodeData, array $destinationNodeDa
}
}

private function getHiddenNodeIds(array $rows): array
/**
* @param int $contentObjectId
*
* @return int[]
*
* @throws \Doctrine\DBAL\Driver\Exception
* @throws \Doctrine\DBAL\Exception
*/
private function getHiddenNodeIds(int $contentObjectId): array
{
return array_map(
static function (array $row) {
return (int)$row['node_id'];
},
array_filter(
$rows,
static function (array $row) {
return !empty($row['is_hidden']);
}
)
);
$query = $this->buildHiddenSubtreeQuery('node_id');
$expr = $query->expr();
$query
->andWhere(
$expr->eq(
'id',
$query->createPositionalParameter(
$contentObjectId,
ParameterType::INTEGER
)
)
);
$statement = $query->execute();

$result = $statement->fetchFirstColumn();

return array_map('intval', $result);
}

/**
* @param int[] $hiddenNodeIds
*/
private function isHiddenByParent(string $pathString, array $hiddenNodeIds): bool
private function isHiddenByParentOrSelf(string $pathString, array $hiddenNodeIds): bool
{
$parentNodeIds = array_map('intval', explode('/', trim($pathString, '/')));
array_pop($parentNodeIds); // remove self
foreach ($parentNodeIds as $parentNodeId) {
if (in_array($parentNodeId, $hiddenNodeIds, true)) {
return true;
Expand Down Expand Up @@ -420,7 +438,7 @@ private function moveSingleSubtreeNode(
$query->set(
'is_invisible',
$query->createPositionalParameter(
$this->isHiddenByParent($newPathString, $hiddenNodeIds) ? 1 : 0,
$this->isHiddenByParentOrSelf($newPathString, $hiddenNodeIds) ? 1 : 0,
ParameterType::INTEGER
)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ public function testMoveSubtreePathUpdate()
$gateway->moveSubtreeNodes(
[
'path_string' => '/1/2/69/',
'contentobject_id' => 67,
'path_identification_string' => 'products',
'is_hidden' => 0,
'is_invisible' => 0,
Expand Down Expand Up @@ -196,6 +197,7 @@ public function testMoveHiddenDestinationUpdate()
$gateway->moveSubtreeNodes(
[
'path_string' => '/1/2/69/',
'contentobject_id' => 67,
'path_identification_string' => 'products',
'is_hidden' => 0,
'is_invisible' => 0,
Expand Down Expand Up @@ -241,6 +243,7 @@ public function testMoveHiddenSourceUpdate()
$gateway->moveSubtreeNodes(
[
'path_string' => '/1/2/69/',
'contentobject_id' => 67,
'path_identification_string' => 'products',
'is_hidden' => 1,
'is_invisible' => 1,
Expand Down Expand Up @@ -287,6 +290,7 @@ public function testMoveHiddenSourceChildUpdate()
$gateway->moveSubtreeNodes(
[
'path_string' => '/1/2/69/',
'contentobject_id' => 67,
'path_identification_string' => 'products',
'is_hidden' => 0,
'is_invisible' => 0,
Expand Down

0 comments on commit fabd714

Please sign in to comment.