Skip to content

Commit

Permalink
EZP-30139: As an editor I want to hide and reveal a content item (#2549)
Browse files Browse the repository at this point in the history
* TMP

* EZP-30139: ContentService interface methods

* EZP-30139: Update db data type

* EZP-30139: Implementation

* EZP-30139: Integration Tests

* EZP-30139: Fix unit tests

* Update data/update/postgres/dbupdate-7.4.0-to-7.5.0.sql

Co-Authored-By: ViniTou <[email protected]>

* EZP-30139: Handle invisible property

* EZP-30139: Add slots for hide/reveal content

* EZP-30139: Fix root path

* EZP-30139: gateway refactor, fix policies exceptions
  • Loading branch information
ViniTou authored and Łukasz Serwatka committed Mar 4, 2019
1 parent 5acabab commit f6e1114
Show file tree
Hide file tree
Showing 36 changed files with 840 additions and 25 deletions.
1 change: 1 addition & 0 deletions data/mysql/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,7 @@ CREATE TABLE `ezcontentobject` (
`remote_id` varchar(100) DEFAULT NULL,
`section_id` int(11) NOT NULL DEFAULT '0',
`status` int(11) DEFAULT '0',
`is_hidden` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `ezcontentobject_remote_id` (`remote_id`),
KEY `ezcontentobject_classid` (`contentclass_id`),
Expand Down
6 changes: 6 additions & 0 deletions data/update/mysql/dbupdate-7.4.0-to-7.5.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,9 @@ ADD CONSTRAINT `ezcontentclass_attribute_ml_lang_fk`
--

ALTER TABLE `eznotification` MODIFY COLUMN `data` TEXT;

--
-- EZP-30139: As an editor I want to hide and reveal a content item
--

ALTER TABLE `ezcontentobject` ADD COLUMN `is_hidden` tinyint(1) NOT NULL DEFAULT '0';
6 changes: 6 additions & 0 deletions data/update/postgres/dbupdate-7.4.0-to-7.5.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,9 @@ ADD CONSTRAINT ezcontentclass_attribute_ml_lang_fk

ALTER TABLE eznotification ALTER COLUMN is_pending TYPE BOOLEAN;
ALTER TABLE eznotification ALTER COLUMN is_pending SET DEFAULT true;

--
-- EZP-30139: As an editor I want to hide and reveal a content item
--

ALTER TABLE ezcontentobject ADD is_hidden boolean DEFAULT false NOT NULL;
22 changes: 22 additions & 0 deletions eZ/Publish/API/Repository/ContentService.php
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,28 @@ public function deleteTranslation(ContentInfo $contentInfo, $languageCode);
*/
public function deleteTranslationFromDraft(VersionInfo $versionInfo, $languageCode);

/**
* Hides Content by making all the Locations appear hidden.
* It does not persist hidden state on Location object itself.
*
* Content hidden by this API can be revealed by revealContent API.
*
* @see revealContent
*
* @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
*/
public function hideContent(ContentInfo $contentInfo): void;

/**
* Reveals Content hidden by hideContent API.
* Locations which were hidden before hiding Content will remain hidden.
*
* @see hideContent
*
* @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
*/
public function revealContent(ContentInfo $contentInfo): void;

/**
* Instantiates a new content create struct object.
*
Expand Down
192 changes: 192 additions & 0 deletions eZ/Publish/API/Repository/Tests/ContentServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6186,4 +6186,196 @@ private function getExpectedMediaContentInfoProperties()
'status' => ContentInfo::STATUS_PUBLISHED,
];
}

/**
* @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct[] $locationsToHide
*
* @dataProvider provideLocationsToHideAndReveal
*/
public function testHideContent(array $locationsToHide)
{
$repository = $this->getRepository();

$contentTypeService = $repository->getContentTypeService();

$contentType = $contentTypeService->loadContentTypeByIdentifier('folder');

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

$contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
$contentCreate->setField('name', 'Folder to hide');

$content = $contentService->createContent(
$contentCreate,
$locationsToHide
);

$publishedContent = $contentService->publishVersion($content->versionInfo);
$locations = $locationService->loadLocations($publishedContent->contentInfo);

// Sanity check
$this->assertCount(3, $locations);
$this->assertEquals(
[
false,
false,
false,
],
array_column($locations, 'hidden')
);

/* BEGIN: Use Case */
$contentService->hideContent($publishedContent->contentInfo);
/* END: Use Case */

$hiddenLocations = $locationService->loadLocations($publishedContent->contentInfo);
$this->assertEquals(
[
true,
true,
true,
],
array_column($hiddenLocations, 'hidden')
);
}

/**
* @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct[] $locationsToHide
*
* @dataProvider provideLocationsToHideAndReveal
*/
public function testRevealContent(array $locationsToReveal)
{
$repository = $this->getRepository();

$contentTypeService = $repository->getContentTypeService();

$contentType = $contentTypeService->loadContentTypeByIdentifier('folder');

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

$contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
$contentCreate->setField('name', 'Folder to hide');

$locationsToReveal[0]->hidden = true;

$content = $contentService->createContent(
$contentCreate,
$locationsToReveal
);

$publishedContent = $contentService->publishVersion($content->versionInfo);
$locations = $locationService->loadLocations($publishedContent->contentInfo);

// Sanity check
$this->assertCount(3, $locations);
$this->assertEquals(
[
true,
false,
false,
],
array_column($locations, 'hidden')
);

/* BEGIN: Use Case */
$contentService->hideContent($publishedContent->contentInfo);

$this->assertEquals(
[
true,
true,
true,
],
array_column($locationService->loadLocations($publishedContent->contentInfo), 'hidden')
);

$contentService->revealContent($publishedContent->contentInfo);
/* END: Use Case */

$this->assertEquals(
[
true,
false,
false,
],
array_column($locationService->loadLocations($publishedContent->contentInfo), 'hidden')
);
}

public function provideLocationsToHideAndReveal()
{
$locationService = $this->getRepository()->getLocationService();

return [
[
[
$mainLocationCreateStruct = $locationService->newLocationCreateStruct(
$this->generateId('location', 2)
),
$otherCreateStruct = $locationService->newLocationCreateStruct(
$this->generateId('location', 5)
),
$thirdCreateStruct = $locationService->newLocationCreateStruct(
$this->generateId('location', 43)
),
],
],
];
}

public function testHideContentWithParentLocation()
{
$repository = $this->getRepository();
$contentTypeService = $repository->getContentTypeService();

$contentType = $contentTypeService->loadContentTypeByIdentifier('folder');

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

$contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
$contentCreate->setField('name', 'Parent');

$content = $contentService->createContent(
$contentCreate,
[
$locationService->newLocationCreateStruct(
$this->generateId('location', 2)
),
]
);

$publishedContent = $contentService->publishVersion($content->versionInfo);

/* BEGIN: Use Case */
$contentService->hideContent($publishedContent->contentInfo);
/* END: Use Case */

$locations = $locationService->loadLocations($publishedContent->contentInfo);

$childContentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
$childContentCreate->setField('name', 'Child');

$childContent = $contentService->createContent(
$childContentCreate,
[
$locationService->newLocationCreateStruct(
$locations[0]->id
),
]
);

$publishedChildContent = $contentService->publishVersion($childContent->versionInfo);

$childLocations = $locationService->loadLocations($publishedChildContent->contentInfo);

$this->assertTrue($locations[0]->hidden);
$this->assertTrue($locations[0]->invisible);

$this->assertFalse($childLocations[0]->hidden);
$this->assertTrue($childLocations[0]->invisible);
}
}
96 changes: 96 additions & 0 deletions eZ/Publish/API/Repository/Tests/SearchServiceLocationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,102 @@ public function testMapLocationDistanceWithCustomFieldSort()
);
}

/**
* Test for the findLocations() method.
*
* @see \eZ\Publish\API\Repository\SearchService::findLocations()
*/
public function testVisibilityCriterionWithHiddenContent()
{
$repository = $this->getRepository();
$contentTypeService = $repository->getContentTypeService();
$contentType = $contentTypeService->loadContentTypeByIdentifier('folder');

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

$testRootContentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
$testRootContentCreate->setField('name', 'Root for test');

$rootContent = $contentService->createContent(
$testRootContentCreate,
[
$locationService->newLocationCreateStruct(
$this->generateId('location', 2)
),
]
);

$publishedRootContent = $contentService->publishVersion($rootContent->versionInfo);

$contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
$contentCreate->setField('name', 'To Hide');

$content = $contentService->createContent(
$contentCreate,
[
$locationService->newLocationCreateStruct(
$publishedRootContent->contentInfo->mainLocationId
),
]
);
$publishedContent = $contentService->publishVersion($content->versionInfo);

$childContentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
$childContentCreate->setField('name', 'Invisible Child');

$childContent = $contentService->createContent(
$childContentCreate,
[
$locationService->newLocationCreateStruct(
$publishedContent->contentInfo->mainLocationId
),
]
);
$rootLocation = $locationService->loadLocation($publishedRootContent->contentInfo->mainLocationId);

$contentService->publishVersion($childContent->versionInfo);
$this->refreshSearch($repository);

$query = new LocationQuery([
'query' => new Criterion\LogicalAnd([
new Criterion\Visibility(
Criterion\Visibility::VISIBLE
),
new Criterion\Subtree(
$rootLocation->pathString
),
]),
]);

//Sanity check for visible locations
$result = $searchService->findLocations($query);
$this->assertEquals(3, $result->totalCount);

//Hide main content
$contentService->hideContent($publishedContent->contentInfo);
$this->refreshSearch($repository);

$result = $searchService->findLocations($query);
$this->assertEquals(1, $result->totalCount);

//Query for invisible content
$hiddenQuery = new LocationQuery([
'query' => new Criterion\LogicalAnd([
new Criterion\Visibility(
Criterion\Visibility::HIDDEN
),
new Criterion\Subtree(
$rootLocation->pathString
),
]),
]);

$result = $searchService->findLocations($hiddenQuery);
$this->assertEquals(2, $result->totalCount);
}

/**
* Assert that query result matches the given fixture.
*
Expand Down
6 changes: 6 additions & 0 deletions eZ/Publish/API/Repository/Values/Content/ContentInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
* @property-read string $mainLanguageCode The main language code of the Content object. If the available flag is set to true the Content is shown in this language if the requested language does not exist.
* @property-read mixed $mainLocationId Identifier of the main location.
* @property-read int $status status of the Content object
* @property-read bool $isHidden status of the Content object
*/
class ContentInfo extends ValueObject
{
Expand Down Expand Up @@ -140,6 +141,11 @@ class ContentInfo extends ValueObject
*/
protected $status;

/**
* @var bool
*/
protected $isHidden;

This comment has been minimized.

Copy link
@pspanja

pspanja Mar 14, 2019

Contributor

This is not in line with the existing naming of properties on the Location object. With this we will have code like:

if ($location->hidden && $content->isHidden) {
    ...
}

Of course that's not a very big deal, but it would still be good to get rid of it before the release.


/**
* @return bool
*/
Expand Down
Loading

0 comments on commit f6e1114

Please sign in to comment.