From 0c21b6143b80c81ecfb9c8d4754bec1ee2139622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 23 May 2025 19:08:18 +0200 Subject: [PATCH 01/59] NGSTACK-977 add 'isHidden' and 'isInvisible' properties to Tag object in both API and persistence layer --- bundle/API/Repository/Values/Tags/Tag.php | 10 ++++++++++ bundle/SPI/Persistence/Tags/Tag.php | 10 ++++++++++ bundle/SPI/Persistence/Tags/TagInfo.php | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/bundle/API/Repository/Values/Tags/Tag.php b/bundle/API/Repository/Values/Tags/Tag.php index 99a6714e..23be6a40 100644 --- a/bundle/API/Repository/Values/Tags/Tag.php +++ b/bundle/API/Repository/Values/Tags/Tag.php @@ -104,6 +104,16 @@ final class Tag extends ValueObject */ protected ?string $prioritizedLanguageCode; + /** + * Indicates if the Tag object is visible or not + */ + protected bool $isHidden; + + /** + * Indicates if the Tag object is located under another hidden Tag object + */ + protected bool $isInvisible; + /** * Construct object optionally with a set of properties. * diff --git a/bundle/SPI/Persistence/Tags/Tag.php b/bundle/SPI/Persistence/Tags/Tag.php index 8fe27331..42ec2d27 100644 --- a/bundle/SPI/Persistence/Tags/Tag.php +++ b/bundle/SPI/Persistence/Tags/Tag.php @@ -72,4 +72,14 @@ final class Tag extends ValueObject * @var int[] */ public array $languageIds = []; + + /** + * Indicates if the tag is visible or not + */ + public bool $isHidden; + + /** + * Indicates if the tag is located under another hidden tag + */ + public bool $isInvisible; } diff --git a/bundle/SPI/Persistence/Tags/TagInfo.php b/bundle/SPI/Persistence/Tags/TagInfo.php index 1d3d23a7..3fc7c22e 100644 --- a/bundle/SPI/Persistence/Tags/TagInfo.php +++ b/bundle/SPI/Persistence/Tags/TagInfo.php @@ -64,4 +64,14 @@ final class TagInfo extends ValueObject * @var int[] */ public array $languageIds = []; + + /** + * Indicates if the tag is visible or not + */ + public bool $isHidden; + + /** + * Indicates if the tag is located under another hidden tag + */ + public bool $isInvisible; } From 71034c0a343ac70097c63e3a2db5405a3529aeab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 23 May 2025 19:11:02 +0200 Subject: [PATCH 02/59] NGSTACK-977 update database schema to include 'is_hidden' and 'is_invisible' columns in 'eztags' table --- bundle/Resources/sql/mysql/schema.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bundle/Resources/sql/mysql/schema.sql b/bundle/Resources/sql/mysql/schema.sql index 6130ee95..9a7197e7 100644 --- a/bundle/Resources/sql/mysql/schema.sql +++ b/bundle/Resources/sql/mysql/schema.sql @@ -9,6 +9,8 @@ CREATE TABLE `eztags` ( `remote_id` varchar(100) NOT NULL default '', `main_language_id` int(11) NOT NULL default '0', `language_mask` int(11) NOT NULL default '0', + `is_hidden` tinyint NOT NULL DEFAULT '0', + `is_invisible` tinyint NOT NULL DEFAULT '0', PRIMARY KEY ( `id` ), KEY `idx_eztags_keyword` ( `keyword`(191) ), KEY `idx_eztags_keyword_id` ( `keyword`(191), `id` ), From 981a985a379f5c3bf199f6a43b52ab04343545d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 23 May 2025 19:22:52 +0200 Subject: [PATCH 03/59] NGSTACK-977 add support for 'isHidden' and 'isInvisible' properties in DoctrineDatabase, TagsMapper and Mapper classes --- .../Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php | 2 ++ bundle/Core/Persistence/Legacy/Tags/Mapper.php | 4 ++++ bundle/Core/Repository/TagsMapper.php | 2 ++ 3 files changed, 8 insertions(+) diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index 02a857dd..e46b1573 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -930,6 +930,8 @@ private function createTagFindQuery(?array $translations = null, bool $useAlways 'eztags.remote_id', 'eztags.main_language_id', 'eztags.language_mask', + 'eztags.is_hidden', + 'eztags.is_invisible', // Tag keywords 'eztags_keyword.keyword', 'eztags_keyword.locale', diff --git a/bundle/Core/Persistence/Legacy/Tags/Mapper.php b/bundle/Core/Persistence/Legacy/Tags/Mapper.php index 024eecdf..8c76a961 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Mapper.php +++ b/bundle/Core/Persistence/Legacy/Tags/Mapper.php @@ -35,6 +35,8 @@ public function createTagInfoFromRow(array $row): TagInfo $tagInfo->alwaysAvailable = (bool) ((int) $row['language_mask'] & 1); $tagInfo->mainLanguageCode = $this->languageHandler->load($row['main_language_id'])->languageCode; $tagInfo->languageIds = $this->languageMaskGenerator->extractLanguageIdsFromMask((int) $row['language_mask']); + $tagInfo->isHidden = (bool) ((int) $row['is_hidden']); + $tagInfo->isInvisible = (bool) ((int) $row['is_invisible']); return $tagInfo; } @@ -60,6 +62,8 @@ public function extractTagListFromRows(array $rows): array $tag->alwaysAvailable = (bool) ((int) $row['language_mask'] & 1); $tag->mainLanguageCode = $this->languageHandler->load($row['main_language_id'])->languageCode; $tag->languageIds = $this->languageMaskGenerator->extractLanguageIdsFromMask((int) $row['language_mask']); + $tag->isHidden = (bool) ((int) $row['is_hidden']); + $tag->isInvisible = (bool) ((int) $row['is_invisible']); $tagList[$tagId] = $tag; } diff --git a/bundle/Core/Repository/TagsMapper.php b/bundle/Core/Repository/TagsMapper.php index 2d94ff7e..7ad0311f 100644 --- a/bundle/Core/Repository/TagsMapper.php +++ b/bundle/Core/Repository/TagsMapper.php @@ -67,6 +67,8 @@ public function buildTagDomainList(array $spiTags, array $prioritizedLanguages = 'mainLanguageCode' => $spiTag->mainLanguageCode, 'languageCodes' => $languageCodes, 'prioritizedLanguageCode' => $prioritizedLanguageCode, + 'isHidden' => $spiTag->isHidden, + 'isInvisible' => $spiTag->isInvisible, ], ); } From d3dc59e3b3025c01ef5ddc13956afa78390ea46c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 23 May 2025 19:26:24 +0200 Subject: [PATCH 04/59] NGSTACK-977 add support for 'isHidden' and 'isInvisible' fields in translation files and display them in admin UI --- bundle/Resources/translations/netgen_tags_admin.en.yml | 2 ++ bundle/Resources/translations/netgen_tags_admin.fr.yml | 2 ++ bundle/Resources/views/admin/tag/children.html.twig | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/bundle/Resources/translations/netgen_tags_admin.en.yml b/bundle/Resources/translations/netgen_tags_admin.en.yml index 34a5ea08..8220fe83 100644 --- a/bundle/Resources/translations/netgen_tags_admin.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin.en.yml @@ -13,6 +13,8 @@ tag.translations: 'Translations' tag.modified: 'Modified' tag.main_tag: 'Main tag' tag.parent_tag: 'Parent tag' +tag.hidden: 'Hidden' +tag.invisible: 'Invisible' tag.content.content_id: 'Content ID' tag.content.name: 'Name' diff --git a/bundle/Resources/translations/netgen_tags_admin.fr.yml b/bundle/Resources/translations/netgen_tags_admin.fr.yml index 2bdf7739..07586606 100644 --- a/bundle/Resources/translations/netgen_tags_admin.fr.yml +++ b/bundle/Resources/translations/netgen_tags_admin.fr.yml @@ -13,6 +13,8 @@ tag.translations: 'Traductions' tag.modified: 'Modifié' tag.main_tag: 'Tag principale' tag.parent_tag: 'Tag parent' +tag.hidden: 'Caché' +tag.invisible: 'Invisible' tag.content.content_id: 'ID du contenu' tag.content.name: 'Nom' diff --git a/bundle/Resources/views/admin/tag/children.html.twig b/bundle/Resources/views/admin/tag/children.html.twig index 7b21158e..54fac275 100644 --- a/bundle/Resources/views/admin/tag/children.html.twig +++ b/bundle/Resources/views/admin/tag/children.html.twig @@ -26,6 +26,8 @@ {{ 'tag.tag_name'|trans }} {{ 'tag.translations'|trans }} {{ 'tag.modified'|trans }} + {{ 'tag.hidden'|trans }} + {{ 'tag.invisible'|trans }} @@ -48,6 +50,8 @@ {% endfor %} {{ child.modificationDate|date }} + {{ child.isHidden ? 1 : 0 }} + {{ child.isInvisible ? 1 : 0 }} {% endfor %} From 62ba8adac87dbb70bfa13660ae3fc2636e6556af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Wed, 4 Jun 2025 16:38:11 +0200 Subject: [PATCH 05/59] NGSTACK-977 add 'Hide tag' button and its functionality in admin interface --- bundle/API/Repository/TagsService.php | 7 +++++ bundle/Controller/Admin/TagController.php | 11 ++++++++ bundle/Core/Event/TagsService.php | 5 ++++ bundle/Core/Persistence/Cache/TagsHandler.php | 8 ++++++ .../Core/Persistence/Legacy/Tags/Gateway.php | 5 ++++ .../Legacy/Tags/Gateway/DoctrineDatabase.php | 27 +++++++++++++++++++ .../Tags/Gateway/ExceptionConversion.php | 11 ++++++++ .../Core/Persistence/Legacy/Tags/Handler.php | 6 +++++ bundle/Core/Repository/TagsService.php | 22 +++++++++++++++ bundle/Core/SiteAccessAware/TagsService.php | 5 ++++ bundle/Resources/config/policies.yaml | 1 + .../Resources/config/routing/admin/tag.yaml | 6 +++++ .../translations/netgen_tags_admin.en.yml | 2 ++ .../translations/netgen_tags_admin.fr.yml | 2 ++ .../netgen_tags_admin_flash.en.yml | 1 + .../Resources/views/admin/tag/show.html.twig | 7 +++++ bundle/SPI/Persistence/Tags/Handler.php | 5 ++++ 17 files changed, 131 insertions(+) diff --git a/bundle/API/Repository/TagsService.php b/bundle/API/Repository/TagsService.php index 9d4f4008..179e18eb 100644 --- a/bundle/API/Repository/TagsService.php +++ b/bundle/API/Repository/TagsService.php @@ -286,6 +286,13 @@ public function newSynonymCreateStruct(int $mainTagId, string $mainLanguageCode) */ public function newTagUpdateStruct(): TagUpdateStruct; + /** + * Hides $tag + * + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException + */ + public function hideTag(Tag $tag): void; + /** * Allows tags API execution to be performed with full access sand-boxed. * diff --git a/bundle/Controller/Admin/TagController.php b/bundle/Controller/Admin/TagController.php index 7d9030df..b989c6ed 100644 --- a/bundle/Controller/Admin/TagController.php +++ b/bundle/Controller/Admin/TagController.php @@ -503,6 +503,17 @@ public function childrenAction(Request $request, ?Tag $tag = null): Response return $this->redirect($request->getPathInfo()); } + public function hideAction(Request $request, Tag $tag): Response + { + $this->denyAccessUnlessGranted('ibexa:tags:hide' . ($tag->isSynonym() ? 'synonym' : '')); + + $this->tagsService->hideTag($tag); + + $this->addFlashMessage('success', 'tag_hidden', ['%tagKeyword%' => $tag->keyword]); + + return $this->redirectToTag($tag); + } + /** * This method is called from a form containing all children tags of a tag. * It shows a confirmation view. diff --git a/bundle/Core/Event/TagsService.php b/bundle/Core/Event/TagsService.php index 816a3470..de01d7a8 100644 --- a/bundle/Core/Event/TagsService.php +++ b/bundle/Core/Event/TagsService.php @@ -226,6 +226,11 @@ public function newTagUpdateStruct(): TagUpdateStruct return $this->service->newTagUpdateStruct(); } + public function hideTag(Tag $tag): void + { + $this->service->hideTag($tag); + } + public function sudo(callable $callback, ?TagsServiceInterface $outerTagsService = null): mixed { return $this->service->sudo($callback, $outerTagsService ?? $this); diff --git a/bundle/Core/Persistence/Cache/TagsHandler.php b/bundle/Core/Persistence/Cache/TagsHandler.php index eadecf1c..d8e4cee9 100644 --- a/bundle/Core/Persistence/Cache/TagsHandler.php +++ b/bundle/Core/Persistence/Cache/TagsHandler.php @@ -304,6 +304,14 @@ public function deleteTag(int $tagId): void $this->cache->invalidateTags(['tag-path-' . $tagId]); } + public function hideTag(int $tagId): void + { + $this->logger->logCall(__METHOD__, ['tag' => $tagId]); + $this->tagsHandler->hideTag($tagId); + + $this->cache->invalidateTags(['tag-path-' . $tagId]); + } + /** * Return relevant cache tags so cache can be purged reliably. * diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway.php b/bundle/Core/Persistence/Legacy/Tags/Gateway.php index 9ad839d1..acf39ab0 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway.php @@ -112,4 +112,9 @@ abstract public function moveSubtree(array $sourceTagData, ?array $destinationPa * If $tagId is a synonym, only the synonym is deleted. */ abstract public function deleteTag(int $tagId): void; + + /** + * Hides tag identified by $tagId + */ + abstract public function hideTag(int $tagId): void; } diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index e46b1573..c6a37edc 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -844,6 +844,33 @@ public function deleteTag(int $tagId): void $query->execute(); } + public function hideTag(int $tagId): void + { + $query = $this->connection->createQueryBuilder(); + $query + ->update('eztags') + ->set('is_hidden', 1) + ->where( + $query->expr()->eq('id', ':tag_id') + )->setParameter('tag_id', $tagId, Types::INTEGER); + + $query->execute(); + + $query + ->update('eztags') + ->set('is_invisible', 1) + ->where( + $query->expr()->like('path_string', ':path_string') + ) + ->andWhere( + $query->expr()->neq('id', ':tag_id') + ) + ->setParameter('path_string', '%/' . $tagId . '/%', Types::STRING) + ->setParameter('tag_id', $tagId, Types::INTEGER); + + $query->execute(); + } + private function createTagIdsQuery(?array $translations = null, bool $useAlwaysAvailable = true): QueryBuilder { $query = $this->connection->createQueryBuilder(); diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php index f982ea2f..92fbf2be 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php @@ -224,4 +224,15 @@ public function deleteTag(int $tagId): void throw new RuntimeException('Database error', 0, $e); } } + + public function hideTag(int $tagId): void + { + try { + $this->innerGateway->hideTag($tagId); + } catch (DBALException $e) { + throw new RuntimeException('Database error', 0, $e); + } catch (PDOException $e) { + throw new RuntimeException('Database error', 0, $e); + } + } } diff --git a/bundle/Core/Persistence/Legacy/Tags/Handler.php b/bundle/Core/Persistence/Legacy/Tags/Handler.php index 3414804b..273ec167 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Handler.php +++ b/bundle/Core/Persistence/Legacy/Tags/Handler.php @@ -219,6 +219,12 @@ public function deleteTag(int $tagId): void $this->gateway->deleteTag($tagInfo->id); } + public function hideTag(int $tagId): void + { + $tagInfo = $this->loadTagInfo($tagId); + $this->gateway->hideTag($tagInfo->id); + } + /** * Copies tag object identified by $sourceData into destination identified by $destinationParentData. * diff --git a/bundle/Core/Repository/TagsService.php b/bundle/Core/Repository/TagsService.php index 0574906d..cd44b13a 100644 --- a/bundle/Core/Repository/TagsService.php +++ b/bundle/Core/Repository/TagsService.php @@ -751,6 +751,28 @@ public function newTagUpdateStruct(): TagUpdateStruct return new TagUpdateStruct(); } + public function hideTag(Tag $tag): void + { + if ($tag->mainTagId > 0) { + if ($this->hasAccess('tags', 'hidesynonym') === false) { + throw new UnauthorizedException('tags', 'hidesynonym'); + } + } elseif ($this->hasAccess('tags', 'hide') === false) { + throw new UnauthorizedException('tags', 'hide'); + } + + $this->repository->beginTransaction(); + + try { + $this->tagsHandler->hideTag($tag->id); + $this->repository->commit(); + } catch (Exception $e) { + $this->repository->rollback(); + + throw $e; + } + } + public function sudo(callable $callback, ?TagsServiceInterface $outerTagsService = null): mixed { ++$this->sudoNestingLevel; diff --git a/bundle/Core/SiteAccessAware/TagsService.php b/bundle/Core/SiteAccessAware/TagsService.php index 37d36a94..3675e7d7 100644 --- a/bundle/Core/SiteAccessAware/TagsService.php +++ b/bundle/Core/SiteAccessAware/TagsService.php @@ -188,6 +188,11 @@ public function newTagUpdateStruct(): TagUpdateStruct return $this->innerService->newTagUpdateStruct(); } + public function hideTag(Tag $tag): void + { + $this->innerService->hideTag($tag); + } + public function sudo(callable $callback, ?TagsServiceInterface $outerTagsService = null): mixed { return $this->innerService->sudo($callback, $outerTagsService ?? $this); diff --git a/bundle/Resources/config/policies.yaml b/bundle/Resources/config/policies.yaml index 1bedf021..4e76fe98 100644 --- a/bundle/Resources/config/policies.yaml +++ b/bundle/Resources/config/policies.yaml @@ -9,3 +9,4 @@ tags: deletesynonym: ~ makesynonym: ~ merge: ~ + hide: ~ diff --git a/bundle/Resources/config/routing/admin/tag.yaml b/bundle/Resources/config/routing/admin/tag.yaml index 8f06b8cf..33cc3782 100644 --- a/bundle/Resources/config/routing/admin/tag.yaml +++ b/bundle/Resources/config/routing/admin/tag.yaml @@ -72,3 +72,9 @@ netgen_tags_admin_tag_children: path: /{tagId}/children controller: netgen_tags.admin.controller.tag:childrenAction methods: [POST] + +netgen_tags_admin_tag_hide: + path: /{tagId}/hide + controller: netgen_tags.admin.controller.tag:hideAction + methods: [GET, POST] + diff --git a/bundle/Resources/translations/netgen_tags_admin.en.yml b/bundle/Resources/translations/netgen_tags_admin.en.yml index 8220fe83..1dbf9fec 100644 --- a/bundle/Resources/translations/netgen_tags_admin.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin.en.yml @@ -72,6 +72,8 @@ tag.add_synonym.title: 'Add synonym' tag.convert.title: 'Convert to synonym' +tag.hide.title: 'Hide tag' + tag.move_tags.title: 'Move tags' tag.move_tags.message: 'Are you sure you want to move the selected tags?' diff --git a/bundle/Resources/translations/netgen_tags_admin.fr.yml b/bundle/Resources/translations/netgen_tags_admin.fr.yml index 07586606..cbdc87b8 100644 --- a/bundle/Resources/translations/netgen_tags_admin.fr.yml +++ b/bundle/Resources/translations/netgen_tags_admin.fr.yml @@ -61,6 +61,8 @@ tag.add_synonym.title: 'Ajouter un synonyme' tag.convert.title: 'Convertir en synonyme' +tag.hide.title: 'Cacher le tag' + tag.move_tags.title: 'Déplacer les tags' tag.move_tags.message: 'Êtes-vous sûr de vouloir déplacer les tags sélectionnés ?' diff --git a/bundle/Resources/translations/netgen_tags_admin_flash.en.yml b/bundle/Resources/translations/netgen_tags_admin_flash.en.yml index a3971a24..ba9bfa5b 100644 --- a/bundle/Resources/translations/netgen_tags_admin_flash.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin_flash.en.yml @@ -15,3 +15,4 @@ success.tags_deleted: 'Tags have been deleted successfully' success.translation_removed: 'Translation for locale "%locale%" has been successfully removed' success.main_translation_set: 'Translation for locale "%locale%" has been set as new main translation' success.always_available_set: 'Always available flag has been successfully updated' +success.tag_hidden: 'Tag "%tagKeyword%" has been hidden' diff --git a/bundle/Resources/views/admin/tag/show.html.twig b/bundle/Resources/views/admin/tag/show.html.twig index 0cdebad0..f7e4e2e9 100644 --- a/bundle/Resources/views/admin/tag/show.html.twig +++ b/bundle/Resources/views/admin/tag/show.html.twig @@ -5,6 +5,9 @@ {% block content %}

{{ 'tag.title'|trans }}: {{ tag.keyword }} + {% if tag.isHidden %} + ({{ 'tag.hidden'|trans|lower }}) + {% endif %} {% if tag.isSynonym %} ({{ 'tag.main_tag'|trans }}: {{ netgen_tags_tag_keyword(tag.mainTagId) }}) @@ -39,6 +42,10 @@ {{ 'tag.convert.title'|trans }} {% endif %} {% endif %} + + {% if is_granted('ibexa:tags:hide' ~ (tag.isSynonym ? 'synonym' : '')) and not tag.isHidden %} + {{ 'tag.hide.title'|trans }} + {% endif %}
diff --git a/bundle/SPI/Persistence/Tags/Handler.php b/bundle/SPI/Persistence/Tags/Handler.php index 164dbec2..1581c4ba 100644 --- a/bundle/SPI/Persistence/Tags/Handler.php +++ b/bundle/SPI/Persistence/Tags/Handler.php @@ -166,4 +166,9 @@ public function moveSubtree(int $sourceId, int $destinationParentId): Tag; * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ public function deleteTag(int $tagId): void; + + /** + * Hides tag identified by $tagId + */ + public function hideTag(int $tagId): void; } From 0ee8a429b1497089b6e6a098cf4446851a0e8494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 5 Jun 2025 09:21:58 +0200 Subject: [PATCH 06/59] NGSTACK-977 add 'Unhide tag' button and its functionality in admin interface --- bundle/API/Repository/TagsService.php | 13 ++++++-- bundle/Controller/Admin/TagController.php | 11 +++++++ bundle/Core/Event/TagsService.php | 5 +++ bundle/Core/Persistence/Cache/TagsHandler.php | 8 +++++ .../Core/Persistence/Legacy/Tags/Gateway.php | 7 +++- .../Legacy/Tags/Gateway/DoctrineDatabase.php | 33 +++++++++++++++++-- .../Tags/Gateway/ExceptionConversion.php | 11 +++++++ .../Core/Persistence/Legacy/Tags/Handler.php | 6 ++++ bundle/Core/Repository/TagsService.php | 22 +++++++++++++ bundle/Core/SiteAccessAware/TagsService.php | 5 +++ bundle/Resources/config/policies.yaml | 1 + .../Resources/config/routing/admin/tag.yaml | 4 +++ .../translations/netgen_tags_admin.en.yml | 1 + .../translations/netgen_tags_admin.fr.yml | 1 + .../netgen_tags_admin_flash.en.yml | 1 + .../Resources/views/admin/tag/show.html.twig | 2 ++ bundle/SPI/Persistence/Tags/Handler.php | 11 ++++++- 17 files changed, 135 insertions(+), 7 deletions(-) diff --git a/bundle/API/Repository/TagsService.php b/bundle/API/Repository/TagsService.php index 179e18eb..984f422c 100644 --- a/bundle/API/Repository/TagsService.php +++ b/bundle/API/Repository/TagsService.php @@ -287,12 +287,21 @@ public function newSynonymCreateStruct(int $mainTagId, string $mainLanguageCode) public function newTagUpdateStruct(): TagUpdateStruct; /** - * Hides $tag + * Hides $tag. * - * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException If the current user is not allowed to delete this tag + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ public function hideTag(Tag $tag): void; + /** + * Unhides $tag. + * + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException If the current user is not allowed to delete this tag + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found + */ + public function unhideTag(Tag $tag): void; + /** * Allows tags API execution to be performed with full access sand-boxed. * diff --git a/bundle/Controller/Admin/TagController.php b/bundle/Controller/Admin/TagController.php index b989c6ed..f4abe186 100644 --- a/bundle/Controller/Admin/TagController.php +++ b/bundle/Controller/Admin/TagController.php @@ -514,6 +514,17 @@ public function hideAction(Request $request, Tag $tag): Response return $this->redirectToTag($tag); } + public function unhideAction(Request $request, Tag $tag): Response + { + $this->denyAccessUnlessGranted('ibexa:tags:unhide' . ($tag->isSynonym() ? 'synonym' : '')); + + $this->tagsService->unhideTag($tag); + + $this->addFlashMessage('success', 'tag_unhidden', ['%tagKeyword%' => $tag->keyword]); + + return $this->redirectToTag($tag); + } + /** * This method is called from a form containing all children tags of a tag. * It shows a confirmation view. diff --git a/bundle/Core/Event/TagsService.php b/bundle/Core/Event/TagsService.php index de01d7a8..b7f047ec 100644 --- a/bundle/Core/Event/TagsService.php +++ b/bundle/Core/Event/TagsService.php @@ -231,6 +231,11 @@ public function hideTag(Tag $tag): void $this->service->hideTag($tag); } + public function unhideTag(Tag $tag): void + { + $this->service->unhideTag($tag); + } + public function sudo(callable $callback, ?TagsServiceInterface $outerTagsService = null): mixed { return $this->service->sudo($callback, $outerTagsService ?? $this); diff --git a/bundle/Core/Persistence/Cache/TagsHandler.php b/bundle/Core/Persistence/Cache/TagsHandler.php index d8e4cee9..77dc3394 100644 --- a/bundle/Core/Persistence/Cache/TagsHandler.php +++ b/bundle/Core/Persistence/Cache/TagsHandler.php @@ -312,6 +312,14 @@ public function hideTag(int $tagId): void $this->cache->invalidateTags(['tag-path-' . $tagId]); } + public function unhideTag(int $tagId): void + { + $this->logger->logCall(__METHOD__, ['tag' => $tagId]); + $this->tagsHandler->unhideTag($tagId); + + $this->cache->invalidateTags(['tag-path-' . $tagId]); + } + /** * Return relevant cache tags so cache can be purged reliably. * diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway.php b/bundle/Core/Persistence/Legacy/Tags/Gateway.php index acf39ab0..bb412072 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway.php @@ -114,7 +114,12 @@ abstract public function moveSubtree(array $sourceTagData, ?array $destinationPa abstract public function deleteTag(int $tagId): void; /** - * Hides tag identified by $tagId + * Hides tag identified by $tagId. */ abstract public function hideTag(int $tagId): void; + + /** + * Unhides tag identified by $tagId. + */ + abstract public function unhideTag(int $tagId): void; } diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index c6a37edc..1c8e1f0e 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -851,7 +851,7 @@ public function hideTag(int $tagId): void ->update('eztags') ->set('is_hidden', 1) ->where( - $query->expr()->eq('id', ':tag_id') + $query->expr()->eq('id', ':tag_id'), )->setParameter('tag_id', $tagId, Types::INTEGER); $query->execute(); @@ -860,10 +860,37 @@ public function hideTag(int $tagId): void ->update('eztags') ->set('is_invisible', 1) ->where( - $query->expr()->like('path_string', ':path_string') + $query->expr()->like('path_string', ':path_string'), ) ->andWhere( - $query->expr()->neq('id', ':tag_id') + $query->expr()->neq('id', ':tag_id'), + ) + ->setParameter('path_string', '%/' . $tagId . '/%', Types::STRING) + ->setParameter('tag_id', $tagId, Types::INTEGER); + + $query->execute(); + } + + public function unhideTag(int $tagId): void + { + $query = $this->connection->createQueryBuilder(); + $query + ->update('eztags') + ->set('is_hidden', 0) + ->where( + $query->expr()->eq('id', ':tag_id'), + )->setParameter('tag_id', $tagId, Types::INTEGER); + + $query->execute(); + + $query + ->update('eztags') + ->set('is_invisible', 0) + ->where( + $query->expr()->like('path_string', ':path_string'), + ) + ->andWhere( + $query->expr()->neq('id', ':tag_id'), ) ->setParameter('path_string', '%/' . $tagId . '/%', Types::STRING) ->setParameter('tag_id', $tagId, Types::INTEGER); diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php index 92fbf2be..ce01ce25 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php @@ -235,4 +235,15 @@ public function hideTag(int $tagId): void throw new RuntimeException('Database error', 0, $e); } } + + public function unhideTag(int $tagId): void + { + try { + $this->innerGateway->unhideTag($tagId); + } catch (DBALException $e) { + throw new RuntimeException('Database error', 0, $e); + } catch (PDOException $e) { + throw new RuntimeException('Database error', 0, $e); + } + } } diff --git a/bundle/Core/Persistence/Legacy/Tags/Handler.php b/bundle/Core/Persistence/Legacy/Tags/Handler.php index 273ec167..5f7f6fb8 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Handler.php +++ b/bundle/Core/Persistence/Legacy/Tags/Handler.php @@ -225,6 +225,12 @@ public function hideTag(int $tagId): void $this->gateway->hideTag($tagInfo->id); } + public function unhideTag(int $tagId): void + { + $tagInfo = $this->loadTagInfo($tagId); + $this->gateway->unhideTag($tagInfo->id); + } + /** * Copies tag object identified by $sourceData into destination identified by $destinationParentData. * diff --git a/bundle/Core/Repository/TagsService.php b/bundle/Core/Repository/TagsService.php index cd44b13a..6b4008bb 100644 --- a/bundle/Core/Repository/TagsService.php +++ b/bundle/Core/Repository/TagsService.php @@ -773,6 +773,28 @@ public function hideTag(Tag $tag): void } } + public function unhideTag(Tag $tag): void + { + if ($tag->mainTagId > 0) { + if ($this->hasAccess('tags', 'unhidesynonym') === false) { + throw new UnauthorizedException('tags', 'hidesynonym'); + } + } elseif ($this->hasAccess('tags', 'unhide') === false) { + throw new UnauthorizedException('tags', 'unhide'); + } + + $this->repository->beginTransaction(); + + try { + $this->tagsHandler->unhideTag($tag->id); + $this->repository->commit(); + } catch (Exception $e) { + $this->repository->rollback(); + + throw $e; + } + } + public function sudo(callable $callback, ?TagsServiceInterface $outerTagsService = null): mixed { ++$this->sudoNestingLevel; diff --git a/bundle/Core/SiteAccessAware/TagsService.php b/bundle/Core/SiteAccessAware/TagsService.php index 3675e7d7..7cf56025 100644 --- a/bundle/Core/SiteAccessAware/TagsService.php +++ b/bundle/Core/SiteAccessAware/TagsService.php @@ -193,6 +193,11 @@ public function hideTag(Tag $tag): void $this->innerService->hideTag($tag); } + public function unhideTag(Tag $tag): void + { + $this->innerService->unhideTag($tag); + } + public function sudo(callable $callback, ?TagsServiceInterface $outerTagsService = null): mixed { return $this->innerService->sudo($callback, $outerTagsService ?? $this); diff --git a/bundle/Resources/config/policies.yaml b/bundle/Resources/config/policies.yaml index 4e76fe98..a0178cd3 100644 --- a/bundle/Resources/config/policies.yaml +++ b/bundle/Resources/config/policies.yaml @@ -10,3 +10,4 @@ tags: makesynonym: ~ merge: ~ hide: ~ + unhide: ~ diff --git a/bundle/Resources/config/routing/admin/tag.yaml b/bundle/Resources/config/routing/admin/tag.yaml index 33cc3782..2f45388a 100644 --- a/bundle/Resources/config/routing/admin/tag.yaml +++ b/bundle/Resources/config/routing/admin/tag.yaml @@ -78,3 +78,7 @@ netgen_tags_admin_tag_hide: controller: netgen_tags.admin.controller.tag:hideAction methods: [GET, POST] +netgen_tags_admin_tag_unhide: + path: /{tagId}/unhide + controller: netgen_tags.admin.controller.tag:unhideAction + methods: [GET, POST] diff --git a/bundle/Resources/translations/netgen_tags_admin.en.yml b/bundle/Resources/translations/netgen_tags_admin.en.yml index 1dbf9fec..e3ad26e5 100644 --- a/bundle/Resources/translations/netgen_tags_admin.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin.en.yml @@ -73,6 +73,7 @@ tag.add_synonym.title: 'Add synonym' tag.convert.title: 'Convert to synonym' tag.hide.title: 'Hide tag' +tag.unhide.title: 'Unhide tag' tag.move_tags.title: 'Move tags' tag.move_tags.message: 'Are you sure you want to move the selected tags?' diff --git a/bundle/Resources/translations/netgen_tags_admin.fr.yml b/bundle/Resources/translations/netgen_tags_admin.fr.yml index cbdc87b8..5447be49 100644 --- a/bundle/Resources/translations/netgen_tags_admin.fr.yml +++ b/bundle/Resources/translations/netgen_tags_admin.fr.yml @@ -62,6 +62,7 @@ tag.add_synonym.title: 'Ajouter un synonyme' tag.convert.title: 'Convertir en synonyme' tag.hide.title: 'Cacher le tag' +tag.unhide.title: 'Désactiver le tag' tag.move_tags.title: 'Déplacer les tags' tag.move_tags.message: 'Êtes-vous sûr de vouloir déplacer les tags sélectionnés ?' diff --git a/bundle/Resources/translations/netgen_tags_admin_flash.en.yml b/bundle/Resources/translations/netgen_tags_admin_flash.en.yml index ba9bfa5b..4c0e6cf2 100644 --- a/bundle/Resources/translations/netgen_tags_admin_flash.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin_flash.en.yml @@ -16,3 +16,4 @@ success.translation_removed: 'Translation for locale "%locale%" has been success success.main_translation_set: 'Translation for locale "%locale%" has been set as new main translation' success.always_available_set: 'Always available flag has been successfully updated' success.tag_hidden: 'Tag "%tagKeyword%" has been hidden' +success.tag_unhidden: 'Tag "%tagKeyword%" has been unhidden' diff --git a/bundle/Resources/views/admin/tag/show.html.twig b/bundle/Resources/views/admin/tag/show.html.twig index f7e4e2e9..6368b221 100644 --- a/bundle/Resources/views/admin/tag/show.html.twig +++ b/bundle/Resources/views/admin/tag/show.html.twig @@ -45,6 +45,8 @@ {% if is_granted('ibexa:tags:hide' ~ (tag.isSynonym ? 'synonym' : '')) and not tag.isHidden %} {{ 'tag.hide.title'|trans }} + {% elseif is_granted('ibexa:tags:unhide' ~ (tag.isSynonym ? 'synonym' : '')) and tag.isHidden %} + {{ 'tag.unhide.title'|trans }} {% endif %}
diff --git a/bundle/SPI/Persistence/Tags/Handler.php b/bundle/SPI/Persistence/Tags/Handler.php index 1581c4ba..e63f50d8 100644 --- a/bundle/SPI/Persistence/Tags/Handler.php +++ b/bundle/SPI/Persistence/Tags/Handler.php @@ -168,7 +168,16 @@ public function moveSubtree(int $sourceId, int $destinationParentId): Tag; public function deleteTag(int $tagId): void; /** - * Hides tag identified by $tagId + * Hides tag identified by $tagId. + * + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ public function hideTag(int $tagId): void; + + /** + * Unhides tag identified by $tagId. + * + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found + */ + public function unhideTag(int $tagId): void; } From 033de91a40b77c28ed5b4595530b41d711b75f22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 5 Jun 2025 09:41:24 +0200 Subject: [PATCH 07/59] NGSTACK-977 fix bug when creating queries and update translations to show when a tag is hidden by parent --- .../Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php | 2 ++ bundle/Resources/translations/netgen_tags_admin.en.yml | 1 + bundle/Resources/translations/netgen_tags_admin.fr.yml | 1 + bundle/Resources/views/admin/tag/show.html.twig | 2 ++ 4 files changed, 6 insertions(+) diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index 1c8e1f0e..17f64257 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -856,6 +856,7 @@ public function hideTag(int $tagId): void $query->execute(); + $query = $this->connection->createQueryBuilder(); $query ->update('eztags') ->set('is_invisible', 1) @@ -883,6 +884,7 @@ public function unhideTag(int $tagId): void $query->execute(); + $query = $this->connection->createQueryBuilder(); $query ->update('eztags') ->set('is_invisible', 0) diff --git a/bundle/Resources/translations/netgen_tags_admin.en.yml b/bundle/Resources/translations/netgen_tags_admin.en.yml index e3ad26e5..fa5cc2ea 100644 --- a/bundle/Resources/translations/netgen_tags_admin.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin.en.yml @@ -15,6 +15,7 @@ tag.main_tag: 'Main tag' tag.parent_tag: 'Parent tag' tag.hidden: 'Hidden' tag.invisible: 'Invisible' +tag.hidden_by_parent: 'hidden by parent' tag.content.content_id: 'Content ID' tag.content.name: 'Name' diff --git a/bundle/Resources/translations/netgen_tags_admin.fr.yml b/bundle/Resources/translations/netgen_tags_admin.fr.yml index 5447be49..88729d6c 100644 --- a/bundle/Resources/translations/netgen_tags_admin.fr.yml +++ b/bundle/Resources/translations/netgen_tags_admin.fr.yml @@ -15,6 +15,7 @@ tag.main_tag: 'Tag principale' tag.parent_tag: 'Tag parent' tag.hidden: 'Caché' tag.invisible: 'Invisible' +tag.hidden_by_parent: 'caché par le parent' tag.content.content_id: 'ID du contenu' tag.content.name: 'Nom' diff --git a/bundle/Resources/views/admin/tag/show.html.twig b/bundle/Resources/views/admin/tag/show.html.twig index 6368b221..2913ed9b 100644 --- a/bundle/Resources/views/admin/tag/show.html.twig +++ b/bundle/Resources/views/admin/tag/show.html.twig @@ -7,6 +7,8 @@ {{ 'tag.title'|trans }}: {{ tag.keyword }} {% if tag.isHidden %} ({{ 'tag.hidden'|trans|lower }}) + {% elseif tag.isInvisible %} + ({{ 'tag.hidden_by_parent'|trans }}) {% endif %} {% if tag.isSynonym %} From b47e3a5bbe12e9beb44ed6f65eca3c1b927ec5b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 5 Jun 2025 11:47:00 +0200 Subject: [PATCH 08/59] NGSTACK-977 add functionality for hiding and unhiding selected children tags --- bundle/Controller/Admin/TagController.php | 72 +++++++++++++++++++ .../Resources/config/routing/admin/tag.yaml | 10 +++ bundle/Resources/public/admin/js/app.js | 24 ++++++- .../translations/netgen_tags_admin.en.yml | 2 + .../translations/netgen_tags_admin.fr.yml | 2 + .../netgen_tags_admin_flash.en.yml | 2 + .../views/admin/tag/children.html.twig | 10 +++ 7 files changed, 121 insertions(+), 1 deletion(-) diff --git a/bundle/Controller/Admin/TagController.php b/bundle/Controller/Admin/TagController.php index f4abe186..d866eff4 100644 --- a/bundle/Controller/Admin/TagController.php +++ b/bundle/Controller/Admin/TagController.php @@ -500,6 +500,24 @@ public function childrenAction(Request $request, ?Tag $tag = null): Response ); } + if ($request->request->has('HideTagsAction')) { + return $this->redirectToRoute( + 'netgen_tags_admin_tag_hide_tags', + [ + 'parentId' => $tag?->id ?? 0, + ], + ); + } + + if ($request->request->has('UnhideTagsAction')) { + return $this->redirectToRoute( + 'netgen_tags_admin_tag_unhide_tags', + [ + 'parentId' => $tag?->id ?? 0, + ], + ); + } + return $this->redirect($request->getPathInfo()); } @@ -688,6 +706,60 @@ public function deleteTagsAction(Request $request, ?Tag $parentTag = null): Resp ); } + public function hideTagsAction(Request $request, ?Tag $parentTag = null): Response + { + $this->denyAccessUnlessGranted('ibexa:tags:hide'); + + $tagIds = (array) $request->request->get( + 'Tags', + $request->hasSession() ? $request->getSession()->get('ngtags_tag_ids') : [], + ); + + if (count($tagIds) === 0) { + return $this->redirectToTag($parentTag); + } + + $tags = []; + foreach ($tagIds as $tagId) { + $tags[] = $this->tagsService->loadTag((int) $tagId); + } + + foreach ($tags as $tagObject) { + $this->tagsService->hideTag($tagObject); + } + + $this->addFlashMessage('success', 'tags_hidden'); + + return $this->redirectToTag($parentTag); + } + + public function unhideTagsAction(Request $request, ?Tag $parentTag = null): Response + { + $this->denyAccessUnlessGranted('ibexa:tags:unhide'); + + $tagIds = (array) $request->request->get( + 'Tags', + $request->hasSession() ? $request->getSession()->get('ngtags_tag_ids') : [], + ); + + if (count($tagIds) === 0) { + return $this->redirectToTag($parentTag); + } + + $tags = []; + foreach ($tagIds as $tagId) { + $tags[] = $this->tagsService->loadTag((int) $tagId); + } + + foreach ($tags as $tagObject) { + $this->tagsService->unhideTag($tagObject); + } + + $this->addFlashMessage('success', 'tags_unhidden'); + + return $this->redirectToTag($parentTag); + } + public function searchTagsAction(Request $request): Response { $this->denyAccessUnlessGranted('ibexa:tags:read'); diff --git a/bundle/Resources/config/routing/admin/tag.yaml b/bundle/Resources/config/routing/admin/tag.yaml index 2f45388a..eb1901c1 100644 --- a/bundle/Resources/config/routing/admin/tag.yaml +++ b/bundle/Resources/config/routing/admin/tag.yaml @@ -38,6 +38,16 @@ netgen_tags_admin_tag_delete_tags: controller: netgen_tags.admin.controller.tag:deleteTagsAction methods: [GET, POST] +netgen_tags_admin_tag_hide_tags: + path: /hide/{parentId} + controller: netgen_tags.admin.controller.tag:hideTagsAction + methods: [GET, POST] + +netgen_tags_admin_tag_unhide_tags: + path: /unhide/{parentId} + controller: netgen_tags.admin.controller.tag:unhideTagsAction + methods: [GET, POST] + netgen_tags_admin_tag_update_select: path: /{tagId}/update controller: netgen_tags.admin.controller.tag:updateTagSelectAction diff --git a/bundle/Resources/public/admin/js/app.js b/bundle/Resources/public/admin/js/app.js index c90f1245..c10a280b 100644 --- a/bundle/Resources/public/admin/js/app.js +++ b/bundle/Resources/public/admin/js/app.js @@ -345,7 +345,29 @@ function ngTagsInit(jQuery){ }); $enabledInputs.on('change', function(e){ var name = e.currentTarget.dataset.enable; - $('input[data-enable="' + name + '"]:checked').length ? $('[data-enabler="' + name + '"]').removeAttr('disabled') : $('[data-enabler="' + name + '"]').attr('disabled', 'disabled'); + + var $checkedBoxes = $('input[data-enable="' + name + '"]:checked'); + var $allButtons = $('[data-enabler="' + name + '"]'); + + $allButtons.prop('disabled', !$checkedBoxes.length); + + if (name === 'Tags') { + var $hideButton = $('button[name="HideTagsAction"]'); + var $unhideButton = $('button[name="UnhideTagsAction"]'); + + var hasHidden = false; + var hasUnhidden = false; + $checkedBoxes.each(function() { + var isHidden = $(this).closest('tr').find('td:eq(5)').text().trim() === '1'; + + isHidden ? hasHidden = true : hasUnhidden = true; + + if (hasHidden && hasUnhidden) return false; + }); + + $hideButton.prop('disabled', hasHidden || !$checkedBoxes.length); + $unhideButton.prop('disabled', hasUnhidden || !$checkedBoxes.length); + } }); } diff --git a/bundle/Resources/translations/netgen_tags_admin.en.yml b/bundle/Resources/translations/netgen_tags_admin.en.yml index fa5cc2ea..e987309d 100644 --- a/bundle/Resources/translations/netgen_tags_admin.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin.en.yml @@ -95,6 +95,8 @@ tag.button.set_main: 'Set main' tag.button.move_selected: 'Move selected tags' tag.button.copy_selected: 'Copy selected tags' tag.button.delete_selected: 'Remove selected tags' +tag.button.hide_selected: 'Hide selected tags' +tag.button.unhide_selected: 'Unhide selected tags' tag.button.continue: 'Continue' tag.tree.top_level_tags: 'Top level tags' diff --git a/bundle/Resources/translations/netgen_tags_admin.fr.yml b/bundle/Resources/translations/netgen_tags_admin.fr.yml index 88729d6c..3f8ad53f 100644 --- a/bundle/Resources/translations/netgen_tags_admin.fr.yml +++ b/bundle/Resources/translations/netgen_tags_admin.fr.yml @@ -84,6 +84,8 @@ tag.button.set_main: 'Définir principal' tag.button.move_selected: 'Déplacer les tags sélectionnées' tag.button.copy_selected: 'Copier les tags sélectionnés' tag.button.delete_selected: 'Supprimer les tags sélectionnés' +tag.button.hide_selected: 'Masquer les tags sélectionnés' +tag.button.unhide_selected: 'Désactiver les balises sélectionnées' tag.button.continue: 'Continuer' tag.tree.top_level_tags: 'Tags de premier niveau' diff --git a/bundle/Resources/translations/netgen_tags_admin_flash.en.yml b/bundle/Resources/translations/netgen_tags_admin_flash.en.yml index 4c0e6cf2..bd98a531 100644 --- a/bundle/Resources/translations/netgen_tags_admin_flash.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin_flash.en.yml @@ -12,6 +12,8 @@ success.tag_converted: 'Tag "%tagKeyword%" has been converted to synonym of tag success.tags_moved: 'Tags have been moved successfully' success.tags_copied: 'Tags have been copied successfully' success.tags_deleted: 'Tags have been deleted successfully' +success.tags_hidden: 'Tags have been hidden successfully' +success.tags_unhidden: 'Tags have been unhidden successfully' success.translation_removed: 'Translation for locale "%locale%" has been successfully removed' success.main_translation_set: 'Translation for locale "%locale%" has been set as new main translation' success.always_available_set: 'Always available flag has been successfully updated' diff --git a/bundle/Resources/views/admin/tag/children.html.twig b/bundle/Resources/views/admin/tag/children.html.twig index 54fac275..2dc59d0b 100644 --- a/bundle/Resources/views/admin/tag/children.html.twig +++ b/bundle/Resources/views/admin/tag/children.html.twig @@ -5,6 +5,8 @@ {% set can_add = is_granted('ibexa:tags:add', tag is defined ? tag : null) %} {% set can_edit = is_granted('ibexa:tags:edit') %} {% set can_delete = is_granted('ibexa:tags:delete') %} +{% set can_hide = is_granted('ibexa:tags:hide') %} +{% set can_unhide = is_granted('ibexa:tags:unhide') %}

{{ 'tag.children.title'|trans }} ({{ childrenTags|length }})

@@ -73,6 +75,14 @@ {% if can_delete %} {% endif %} + + {% if can_hide %} + + {% endif %} + + {% if can_unhide %} + + {% endif %} {% else %} From 302837dc5e3d7a00bc2cd884d2b63266a0db5396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 5 Jun 2025 12:04:48 +0200 Subject: [PATCH 09/59] NGSTACK-977 throw 404 on frontend if tag is hidden --- bundle/Controller/TagViewController.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bundle/Controller/TagViewController.php b/bundle/Controller/TagViewController.php index 1ae15b3e..d1e10e34 100644 --- a/bundle/Controller/TagViewController.php +++ b/bundle/Controller/TagViewController.php @@ -14,6 +14,14 @@ final class TagViewController extends Controller */ public function viewAction(TagView $view): TagView { + if ($view->getTag()->isHidden) { + throw $this->createNotFoundException('Tag is hidden.'); + } + + if ($view->getTag()->isInvisible) { + throw $this->createNotFoundException('Tag is hidden by parent.'); + } + return $view; } } From fcabf767ada20122b3df504d87043843850343be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 5 Jun 2025 16:32:16 +0200 Subject: [PATCH 10/59] NGSTACK-977 add 'disabled' property to hidden tags and disable adding hidden tags to content --- bundle/Controller/Admin/TreeController.php | 2 ++ bundle/Resources/public/admin/js/app.js | 25 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/bundle/Controller/Admin/TreeController.php b/bundle/Controller/Admin/TreeController.php index e74a32d0..7b6d6827 100644 --- a/bundle/Controller/Admin/TreeController.php +++ b/bundle/Controller/Admin/TreeController.php @@ -126,6 +126,8 @@ private function getTagTreeData(Tag $tag, bool $isRoot = false): array 'parent' => $isRoot ? '#' : $tag->parentTagId, 'text' => $synonymCount > 0 ? $this->escape($tag->keyword) . ' (+' . $synonymCount . ')' : $this->escape($tag->keyword), 'children' => $this->tagsService->getTagChildrenCount($tag) > 0, + 'hidden' => $tag->isHidden, + 'invisible' => $tag->isInvisible, 'a_attr' => [ 'href' => str_replace(':tagId', (string) $tag->id, $this->treeLinks['show_tag']), 'rel' => $tag->id, diff --git a/bundle/Resources/public/admin/js/app.js b/bundle/Resources/public/admin/js/app.js index c10a280b..06695062 100644 --- a/bundle/Resources/public/admin/js/app.js +++ b/bundle/Resources/public/admin/js/app.js @@ -82,6 +82,25 @@ jQuery.noConflict(); if (self.disableSubtree !== '') { self.disableNode(self.disableSubtree); } + + if (data.node && + data.node.original && + (data.node.original.hidden === true || data.node.original.invisible === true)) { + + self.disableNode(data.node.id); + } + + if (data.node && data.node.children) { + data.node.children.forEach(function(childId) { + var childNode = self.$tree.jstree(true).get_node(childId); + if (childNode && + childNode.original && + (childNode.original.hidden === true || childNode.original.invisible === true)) { + + self.disableNode(childId); + } + }); + } }).on('click', '.jstree-anchor', function (event) { var selectedNode = $(this).jstree(true).get_node($(this)); @@ -104,6 +123,12 @@ jQuery.noConflict(); if (!self.settings.modal) { document.location.href = selectedNode.a_attr.href; } else { + if (selectedNode.original && + (selectedNode.original.hidden === true || selectedNode.original.invisible === true)) { + + return false; + } + self.$el.find('input.tag-id').val(selectedNode.id); if (selectedNode.text === undefined || selectedNode.id == '0') { From 402ca4ca647ca6c37d78fcbc316a7ab65c9884e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 6 Jun 2025 10:22:11 +0200 Subject: [PATCH 11/59] NGSTACK-977 add 'hidden' text after hidden tags in eztags content field --- .../views/admin/eztags_content_field.html.twig | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/bundle/Resources/views/admin/eztags_content_field.html.twig b/bundle/Resources/views/admin/eztags_content_field.html.twig index 535befea..22991dce 100644 --- a/bundle/Resources/views/admin/eztags_content_field.html.twig +++ b/bundle/Resources/views/admin/eztags_content_field.html.twig @@ -1,5 +1,15 @@ {% block eztags_field %} {% for tag in field.value.tags %} - {{ tag.keyword }}{% if not loop.last %}, {% endif %} + + {{ tag.keyword }} + {% if tag.isHidden %} + (hidden) + {% elseif tag.isInvisible %} + (hidden by parent) + {% endif %} + + {% if not loop.last %}, {% endif %} {% endfor %} {% endblock %} From f12c26273cef1d988bcf20bd5b52500bc8aa76cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 6 Jun 2025 11:50:46 +0200 Subject: [PATCH 12/59] NGSTACK-977 fix php-cs-fixer and phpstan reports --- bundle/API/Repository/Values/Tags/Tag.php | 6 ++++-- .../Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php | 8 ++++---- bundle/SPI/Persistence/Tags/Tag.php | 4 ++-- bundle/SPI/Persistence/Tags/TagInfo.php | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/bundle/API/Repository/Values/Tags/Tag.php b/bundle/API/Repository/Values/Tags/Tag.php index 23be6a40..d60d2d67 100644 --- a/bundle/API/Repository/Values/Tags/Tag.php +++ b/bundle/API/Repository/Values/Tags/Tag.php @@ -28,6 +28,8 @@ * @property-read bool $alwaysAvailable Indicates if the Tag object is shown in the main language if it is not present in an other requested language * @property-read string $mainLanguageCode The main language code of the Tag object * @property-read string[] $languageCodes List of languages in this Tag object + * @property-read bool $isHidden Indicates if the Tag object is visible or not + * @property-read bool $isInvisible Indicates if the Tag object is located under another hidden Tag object */ final class Tag extends ValueObject { @@ -105,12 +107,12 @@ final class Tag extends ValueObject protected ?string $prioritizedLanguageCode; /** - * Indicates if the Tag object is visible or not + * Indicates if the Tag object is visible or not. */ protected bool $isHidden; /** - * Indicates if the Tag object is located under another hidden Tag object + * Indicates if the Tag object is located under another hidden Tag object. */ protected bool $isInvisible; diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index 17f64257..50f528de 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -849,7 +849,7 @@ public function hideTag(int $tagId): void $query = $this->connection->createQueryBuilder(); $query ->update('eztags') - ->set('is_hidden', 1) + ->set('is_hidden', '1') ->where( $query->expr()->eq('id', ':tag_id'), )->setParameter('tag_id', $tagId, Types::INTEGER); @@ -859,7 +859,7 @@ public function hideTag(int $tagId): void $query = $this->connection->createQueryBuilder(); $query ->update('eztags') - ->set('is_invisible', 1) + ->set('is_invisible', '1') ->where( $query->expr()->like('path_string', ':path_string'), ) @@ -877,7 +877,7 @@ public function unhideTag(int $tagId): void $query = $this->connection->createQueryBuilder(); $query ->update('eztags') - ->set('is_hidden', 0) + ->set('is_hidden', '0') ->where( $query->expr()->eq('id', ':tag_id'), )->setParameter('tag_id', $tagId, Types::INTEGER); @@ -887,7 +887,7 @@ public function unhideTag(int $tagId): void $query = $this->connection->createQueryBuilder(); $query ->update('eztags') - ->set('is_invisible', 0) + ->set('is_invisible', '0') ->where( $query->expr()->like('path_string', ':path_string'), ) diff --git a/bundle/SPI/Persistence/Tags/Tag.php b/bundle/SPI/Persistence/Tags/Tag.php index 42ec2d27..c6175e28 100644 --- a/bundle/SPI/Persistence/Tags/Tag.php +++ b/bundle/SPI/Persistence/Tags/Tag.php @@ -74,12 +74,12 @@ final class Tag extends ValueObject public array $languageIds = []; /** - * Indicates if the tag is visible or not + * Indicates if the tag is visible or not. */ public bool $isHidden; /** - * Indicates if the tag is located under another hidden tag + * Indicates if the tag is located under another hidden tag. */ public bool $isInvisible; } diff --git a/bundle/SPI/Persistence/Tags/TagInfo.php b/bundle/SPI/Persistence/Tags/TagInfo.php index 3fc7c22e..33f057e7 100644 --- a/bundle/SPI/Persistence/Tags/TagInfo.php +++ b/bundle/SPI/Persistence/Tags/TagInfo.php @@ -66,12 +66,12 @@ final class TagInfo extends ValueObject public array $languageIds = []; /** - * Indicates if the tag is visible or not + * Indicates if the tag is visible or not. */ public bool $isHidden; /** - * Indicates if the tag is located under another hidden tag + * Indicates if the tag is located under another hidden tag. */ public bool $isInvisible; } From 981391433d373379bdbff5f16e55eba2f765c56c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 6 Jun 2025 12:22:11 +0200 Subject: [PATCH 13/59] NGSTACK-977 add 'is_hidden' and 'is_invisible' fields to test database schemas and fix MapperTest --- tests/Core/Persistence/Legacy/Tags/MapperTest.php | 8 ++++++++ tests/_fixtures/schema/schema.mysql.sql | 2 ++ tests/_fixtures/schema/schema.postgresql.sql | 4 +++- tests/_fixtures/schema/schema.sqlite.sql | 4 +++- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/tests/Core/Persistence/Legacy/Tags/MapperTest.php b/tests/Core/Persistence/Legacy/Tags/MapperTest.php index 9e1ec38c..5dfc6f60 100644 --- a/tests/Core/Persistence/Legacy/Tags/MapperTest.php +++ b/tests/Core/Persistence/Legacy/Tags/MapperTest.php @@ -28,6 +28,8 @@ final class MapperTest extends TestCase 'remote_id' => '123456abcdef', 'main_language_id' => 8, 'language_mask' => 9, + 'is_hidden' => 0, + 'is_invisible' => 0, ]; /** @@ -47,6 +49,8 @@ final class MapperTest extends TestCase 'language_mask' => 9, 'keyword' => 'Croatia', 'locale' => 'eng-GB', + 'is_hidden' => 0, + 'is_invisible' => 0, ]; /** @@ -65,6 +69,8 @@ final class MapperTest extends TestCase 'alwaysAvailable' => true, 'mainLanguageCode' => 'eng-GB', 'languageIds' => [8], + 'isHidden' => false, + 'isInvisible' => false, ]; /** @@ -84,6 +90,8 @@ final class MapperTest extends TestCase 'alwaysAvailable' => true, 'mainLanguageCode' => 'eng-GB', 'languageIds' => [8], + 'isHidden' => false, + 'isInvisible' => false, ]; private Mapper $tagsMapper; diff --git a/tests/_fixtures/schema/schema.mysql.sql b/tests/_fixtures/schema/schema.mysql.sql index b59724fd..5fa5af41 100644 --- a/tests/_fixtures/schema/schema.mysql.sql +++ b/tests/_fixtures/schema/schema.mysql.sql @@ -11,6 +11,8 @@ CREATE TABLE `eztags` ( `remote_id` varchar(100) NOT NULL DEFAULT '', `main_language_id` int(11) NOT NULL DEFAULT '0', `language_mask` int(11) NOT NULL DEFAULT '0', + `is_hidden` tinyint NOT NULL DEFAULT '0', + `is_invisible` tinyint NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `eztags_remote_id` (`remote_id`), KEY `eztags_keyword` (`keyword`), diff --git a/tests/_fixtures/schema/schema.postgresql.sql b/tests/_fixtures/schema/schema.postgresql.sql index 8107505c..9bf558d7 100644 --- a/tests/_fixtures/schema/schema.postgresql.sql +++ b/tests/_fixtures/schema/schema.postgresql.sql @@ -26,7 +26,9 @@ CREATE TABLE eztags ( modified integer DEFAULT 0 NOT NULL, remote_id character varying(100) DEFAULT ''::character varying NOT NULL, main_language_id integer DEFAULT 0 NOT NULL, - language_mask integer DEFAULT 0 NOT NULL + language_mask integer DEFAULT 0 NOT NULL, + is_hidden integer DEFAULT 0 NOT NULL, + is_invisible integer DEFAULT 0 NOT NULL ); DROP TABLE IF EXISTS eztags_attribute_link; diff --git a/tests/_fixtures/schema/schema.sqlite.sql b/tests/_fixtures/schema/schema.sqlite.sql index e93ecd60..3abc0ee4 100644 --- a/tests/_fixtures/schema/schema.sqlite.sql +++ b/tests/_fixtures/schema/schema.sqlite.sql @@ -10,7 +10,9 @@ CREATE TABLE 'eztags' ( 'modified' integer NOT NULL DEFAULT 0, 'remote_id' text(100) NOT NULL DEFAULT '', 'main_language_id' integer NOT NULL DEFAULT 0, - 'language_mask' integer NOT NULL DEFAULT 0 + 'language_mask' integer NOT NULL DEFAULT 0, + 'is_hidden' integer NOT NULL DEFAULT 0, + 'is_invisible' integer NOT NULL DEFAULT 0 ); DROP TABLE IF EXISTS 'eztags_attribute_link'; From 99872860b3738fe5500e2381134f3380e81a433b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 6 Jun 2025 12:46:05 +0200 Subject: [PATCH 14/59] NGSTACK-977 fix TagsIntegrationTest by adding 'isHidden' and 'isInvisible' fields --- tests/API/Repository/FieldType/TagsIntegrationTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/API/Repository/FieldType/TagsIntegrationTest.php b/tests/API/Repository/FieldType/TagsIntegrationTest.php index 2cd0c5d4..e27b07f6 100644 --- a/tests/API/Repository/FieldType/TagsIntegrationTest.php +++ b/tests/API/Repository/FieldType/TagsIntegrationTest.php @@ -253,6 +253,8 @@ private function getTag1(): Tag 'mainLanguageCode' => 'eng-GB', 'languageCodes' => ['eng-GB'], 'prioritizedLanguageCode' => 'eng-GB', + 'isHidden' => false, + 'isInvisible' => false, ], ); } @@ -276,6 +278,8 @@ private function getTag2(): Tag 'mainLanguageCode' => 'eng-GB', 'languageCodes' => ['eng-GB'], 'prioritizedLanguageCode' => 'eng-GB', + 'isHidden' => false, + 'isInvisible' => false, ], ); } @@ -299,6 +303,8 @@ private function getTag3(): Tag 'mainLanguageCode' => 'eng-GB', 'languageCodes' => ['eng-GB'], 'prioritizedLanguageCode' => 'eng-GB', + 'isHidden' => false, + 'isInvisible' => false, ], ); } From c698f263fc232e8ac50a350b7362d9f5ccca6bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 6 Jun 2025 13:06:39 +0200 Subject: [PATCH 15/59] NGSTACK-977 update phpdocs and remove tag visibility information being shown to the user --- bundle/API/Repository/TagsService.php | 4 ++-- bundle/Controller/TagViewController.php | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/bundle/API/Repository/TagsService.php b/bundle/API/Repository/TagsService.php index 984f422c..8a0b98ed 100644 --- a/bundle/API/Repository/TagsService.php +++ b/bundle/API/Repository/TagsService.php @@ -289,7 +289,7 @@ public function newTagUpdateStruct(): TagUpdateStruct; /** * Hides $tag. * - * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException If the current user is not allowed to delete this tag + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException If the current user is not allowed to hide this tag * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ public function hideTag(Tag $tag): void; @@ -297,7 +297,7 @@ public function hideTag(Tag $tag): void; /** * Unhides $tag. * - * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException If the current user is not allowed to delete this tag + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException If the current user is not allowed to unhide this tag * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ public function unhideTag(Tag $tag): void; diff --git a/bundle/Controller/TagViewController.php b/bundle/Controller/TagViewController.php index d1e10e34..3ca17483 100644 --- a/bundle/Controller/TagViewController.php +++ b/bundle/Controller/TagViewController.php @@ -14,12 +14,8 @@ final class TagViewController extends Controller */ public function viewAction(TagView $view): TagView { - if ($view->getTag()->isHidden) { - throw $this->createNotFoundException('Tag is hidden.'); - } - if ($view->getTag()->isInvisible) { - throw $this->createNotFoundException('Tag is hidden by parent.'); + throw $this->createNotFoundException(); } return $view; From f8bcf8d7540a357d4899b6cf99066d04e54e1e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 6 Jun 2025 13:20:13 +0200 Subject: [PATCH 16/59] NGSTACK-977 modify gateway to make the hidden tag also invisible --- .../Legacy/Tags/Gateway/DoctrineDatabase.php | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index 50f528de..f14d46e8 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -863,11 +863,7 @@ public function hideTag(int $tagId): void ->where( $query->expr()->like('path_string', ':path_string'), ) - ->andWhere( - $query->expr()->neq('id', ':tag_id'), - ) - ->setParameter('path_string', '%/' . $tagId . '/%', Types::STRING) - ->setParameter('tag_id', $tagId, Types::INTEGER); + ->setParameter('path_string', '%/' . $tagId . '/%', Types::STRING); $query->execute(); } @@ -891,11 +887,7 @@ public function unhideTag(int $tagId): void ->where( $query->expr()->like('path_string', ':path_string'), ) - ->andWhere( - $query->expr()->neq('id', ':tag_id'), - ) - ->setParameter('path_string', '%/' . $tagId . '/%', Types::STRING) - ->setParameter('tag_id', $tagId, Types::INTEGER); + ->setParameter('path_string', '%/' . $tagId . '/%', Types::STRING); $query->execute(); } From e5b2f5f16e989715fe5a87042db88dcd9780effb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 6 Jun 2025 13:32:43 +0200 Subject: [PATCH 17/59] NGSTACK-977 remove unnecessary cast to int for 'is_hidden' and 'is_invisible' fields in Mapper --- bundle/Core/Persistence/Legacy/Tags/Mapper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundle/Core/Persistence/Legacy/Tags/Mapper.php b/bundle/Core/Persistence/Legacy/Tags/Mapper.php index 8c76a961..e7e48e4b 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Mapper.php +++ b/bundle/Core/Persistence/Legacy/Tags/Mapper.php @@ -35,8 +35,8 @@ public function createTagInfoFromRow(array $row): TagInfo $tagInfo->alwaysAvailable = (bool) ((int) $row['language_mask'] & 1); $tagInfo->mainLanguageCode = $this->languageHandler->load($row['main_language_id'])->languageCode; $tagInfo->languageIds = $this->languageMaskGenerator->extractLanguageIdsFromMask((int) $row['language_mask']); - $tagInfo->isHidden = (bool) ((int) $row['is_hidden']); - $tagInfo->isInvisible = (bool) ((int) $row['is_invisible']); + $tagInfo->isHidden = (bool) $row['is_hidden']; + $tagInfo->isInvisible = (bool) $row['is_invisible']; return $tagInfo; } From 7e88bdde7cd76a13bee70f33be1009e27885f088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 6 Jun 2025 13:34:54 +0200 Subject: [PATCH 18/59] NGSTACK-977 add 'hidesynonym' and 'unhidesynonym' policies --- bundle/Resources/config/policies.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bundle/Resources/config/policies.yaml b/bundle/Resources/config/policies.yaml index a0178cd3..085b07c6 100644 --- a/bundle/Resources/config/policies.yaml +++ b/bundle/Resources/config/policies.yaml @@ -11,3 +11,5 @@ tags: merge: ~ hide: ~ unhide: ~ + hidesynonym: ~ + unhidesynonym: ~ From dece52cad1c85d0ca6adca828b40db5fbe8cbf16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 6 Jun 2025 13:45:36 +0200 Subject: [PATCH 19/59] NGSTACK-977 add translation domain and make tag visibility info translatable in 'eztags' content field --- bundle/Resources/views/admin/eztags_content_field.html.twig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bundle/Resources/views/admin/eztags_content_field.html.twig b/bundle/Resources/views/admin/eztags_content_field.html.twig index 22991dce..b7775908 100644 --- a/bundle/Resources/views/admin/eztags_content_field.html.twig +++ b/bundle/Resources/views/admin/eztags_content_field.html.twig @@ -1,3 +1,5 @@ +{% trans_default_domain 'netgen_tags_admin' %} + {% block eztags_field %} {% for tag in field.value.tags %} {{ tag.keyword }} {% if tag.isHidden %} - (hidden) + ({{ 'tag.hidden'|trans|lower }}) {% elseif tag.isInvisible %} - (hidden by parent) + ({{ 'tag.hidden_by_parent'|trans }}) {% endif %} {% if not loop.last %}, {% endif %} From 543afc4bebad2f73827f441de210c0464723802f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Fri, 6 Jun 2025 14:16:52 +0200 Subject: [PATCH 20/59] NGSTACK-977 change all 'unhide' text to 'reveal' regarding the tags visibility --- bundle/API/Repository/TagsService.php | 6 +++--- bundle/Controller/Admin/TagController.php | 20 +++++++++---------- bundle/Core/Event/TagsService.php | 4 ++-- bundle/Core/Persistence/Cache/TagsHandler.php | 4 ++-- .../Core/Persistence/Legacy/Tags/Gateway.php | 4 ++-- .../Legacy/Tags/Gateway/DoctrineDatabase.php | 2 +- .../Tags/Gateway/ExceptionConversion.php | 4 ++-- .../Core/Persistence/Legacy/Tags/Handler.php | 4 ++-- bundle/Core/Repository/TagsService.php | 12 +++++------ bundle/Core/SiteAccessAware/TagsService.php | 4 ++-- bundle/Resources/config/policies.yaml | 4 ++-- .../Resources/config/routing/admin/tag.yaml | 12 +++++------ bundle/Resources/public/admin/js/app.js | 10 +++++----- .../translations/netgen_tags_admin.en.yml | 4 ++-- .../translations/netgen_tags_admin.fr.yml | 4 ++-- .../netgen_tags_admin_flash.en.yml | 4 ++-- .../views/admin/tag/children.html.twig | 6 +++--- .../Resources/views/admin/tag/show.html.twig | 4 ++-- bundle/SPI/Persistence/Tags/Handler.php | 4 ++-- 19 files changed, 58 insertions(+), 58 deletions(-) diff --git a/bundle/API/Repository/TagsService.php b/bundle/API/Repository/TagsService.php index 8a0b98ed..a16ebf8b 100644 --- a/bundle/API/Repository/TagsService.php +++ b/bundle/API/Repository/TagsService.php @@ -295,12 +295,12 @@ public function newTagUpdateStruct(): TagUpdateStruct; public function hideTag(Tag $tag): void; /** - * Unhides $tag. + * Reveal $tag. * - * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException If the current user is not allowed to unhide this tag + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException If the current user is not allowed to reveal this tag * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ - public function unhideTag(Tag $tag): void; + public function revealTag(Tag $tag): void; /** * Allows tags API execution to be performed with full access sand-boxed. diff --git a/bundle/Controller/Admin/TagController.php b/bundle/Controller/Admin/TagController.php index d866eff4..fa54400c 100644 --- a/bundle/Controller/Admin/TagController.php +++ b/bundle/Controller/Admin/TagController.php @@ -509,9 +509,9 @@ public function childrenAction(Request $request, ?Tag $tag = null): Response ); } - if ($request->request->has('UnhideTagsAction')) { + if ($request->request->has('RevealTagsAction')) { return $this->redirectToRoute( - 'netgen_tags_admin_tag_unhide_tags', + 'netgen_tags_admin_tag_reveal_tags', [ 'parentId' => $tag?->id ?? 0, ], @@ -532,13 +532,13 @@ public function hideAction(Request $request, Tag $tag): Response return $this->redirectToTag($tag); } - public function unhideAction(Request $request, Tag $tag): Response + public function revealAction(Request $request, Tag $tag): Response { - $this->denyAccessUnlessGranted('ibexa:tags:unhide' . ($tag->isSynonym() ? 'synonym' : '')); + $this->denyAccessUnlessGranted('ibexa:tags:reveal' . ($tag->isSynonym() ? 'synonym' : '')); - $this->tagsService->unhideTag($tag); + $this->tagsService->revealTag($tag); - $this->addFlashMessage('success', 'tag_unhidden', ['%tagKeyword%' => $tag->keyword]); + $this->addFlashMessage('success', 'tag_reveal', ['%tagKeyword%' => $tag->keyword]); return $this->redirectToTag($tag); } @@ -733,9 +733,9 @@ public function hideTagsAction(Request $request, ?Tag $parentTag = null): Respon return $this->redirectToTag($parentTag); } - public function unhideTagsAction(Request $request, ?Tag $parentTag = null): Response + public function revealTagsAction(Request $request, ?Tag $parentTag = null): Response { - $this->denyAccessUnlessGranted('ibexa:tags:unhide'); + $this->denyAccessUnlessGranted('ibexa:tags:reveal'); $tagIds = (array) $request->request->get( 'Tags', @@ -752,10 +752,10 @@ public function unhideTagsAction(Request $request, ?Tag $parentTag = null): Resp } foreach ($tags as $tagObject) { - $this->tagsService->unhideTag($tagObject); + $this->tagsService->revealTag($tagObject); } - $this->addFlashMessage('success', 'tags_unhidden'); + $this->addFlashMessage('success', 'tags_reveal'); return $this->redirectToTag($parentTag); } diff --git a/bundle/Core/Event/TagsService.php b/bundle/Core/Event/TagsService.php index b7f047ec..9b0505fd 100644 --- a/bundle/Core/Event/TagsService.php +++ b/bundle/Core/Event/TagsService.php @@ -231,9 +231,9 @@ public function hideTag(Tag $tag): void $this->service->hideTag($tag); } - public function unhideTag(Tag $tag): void + public function revealTag(Tag $tag): void { - $this->service->unhideTag($tag); + $this->service->revealTag($tag); } public function sudo(callable $callback, ?TagsServiceInterface $outerTagsService = null): mixed diff --git a/bundle/Core/Persistence/Cache/TagsHandler.php b/bundle/Core/Persistence/Cache/TagsHandler.php index 77dc3394..ca24270b 100644 --- a/bundle/Core/Persistence/Cache/TagsHandler.php +++ b/bundle/Core/Persistence/Cache/TagsHandler.php @@ -312,10 +312,10 @@ public function hideTag(int $tagId): void $this->cache->invalidateTags(['tag-path-' . $tagId]); } - public function unhideTag(int $tagId): void + public function revealTag(int $tagId): void { $this->logger->logCall(__METHOD__, ['tag' => $tagId]); - $this->tagsHandler->unhideTag($tagId); + $this->tagsHandler->revealTag($tagId); $this->cache->invalidateTags(['tag-path-' . $tagId]); } diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway.php b/bundle/Core/Persistence/Legacy/Tags/Gateway.php index bb412072..51d76678 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway.php @@ -119,7 +119,7 @@ abstract public function deleteTag(int $tagId): void; abstract public function hideTag(int $tagId): void; /** - * Unhides tag identified by $tagId. + * Reveals tag identified by $tagId. */ - abstract public function unhideTag(int $tagId): void; + abstract public function revealTag(int $tagId): void; } diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index f14d46e8..226f406d 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -868,7 +868,7 @@ public function hideTag(int $tagId): void $query->execute(); } - public function unhideTag(int $tagId): void + public function revealTag(int $tagId): void { $query = $this->connection->createQueryBuilder(); $query diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php index ce01ce25..9ad5dfe4 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php @@ -236,10 +236,10 @@ public function hideTag(int $tagId): void } } - public function unhideTag(int $tagId): void + public function revealTag(int $tagId): void { try { - $this->innerGateway->unhideTag($tagId); + $this->innerGateway->revealTag($tagId); } catch (DBALException $e) { throw new RuntimeException('Database error', 0, $e); } catch (PDOException $e) { diff --git a/bundle/Core/Persistence/Legacy/Tags/Handler.php b/bundle/Core/Persistence/Legacy/Tags/Handler.php index 5f7f6fb8..c2f4f616 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Handler.php +++ b/bundle/Core/Persistence/Legacy/Tags/Handler.php @@ -225,10 +225,10 @@ public function hideTag(int $tagId): void $this->gateway->hideTag($tagInfo->id); } - public function unhideTag(int $tagId): void + public function revealTag(int $tagId): void { $tagInfo = $this->loadTagInfo($tagId); - $this->gateway->unhideTag($tagInfo->id); + $this->gateway->revealTag($tagInfo->id); } /** diff --git a/bundle/Core/Repository/TagsService.php b/bundle/Core/Repository/TagsService.php index 6b4008bb..fb41da59 100644 --- a/bundle/Core/Repository/TagsService.php +++ b/bundle/Core/Repository/TagsService.php @@ -773,20 +773,20 @@ public function hideTag(Tag $tag): void } } - public function unhideTag(Tag $tag): void + public function revealTag(Tag $tag): void { if ($tag->mainTagId > 0) { - if ($this->hasAccess('tags', 'unhidesynonym') === false) { - throw new UnauthorizedException('tags', 'hidesynonym'); + if ($this->hasAccess('tags', 'revealsynonym') === false) { + throw new UnauthorizedException('tags', 'revealsynonym'); } - } elseif ($this->hasAccess('tags', 'unhide') === false) { - throw new UnauthorizedException('tags', 'unhide'); + } elseif ($this->hasAccess('tags', 'reveal') === false) { + throw new UnauthorizedException('tags', 'reveal'); } $this->repository->beginTransaction(); try { - $this->tagsHandler->unhideTag($tag->id); + $this->tagsHandler->revealTag($tag->id); $this->repository->commit(); } catch (Exception $e) { $this->repository->rollback(); diff --git a/bundle/Core/SiteAccessAware/TagsService.php b/bundle/Core/SiteAccessAware/TagsService.php index 7cf56025..5362195d 100644 --- a/bundle/Core/SiteAccessAware/TagsService.php +++ b/bundle/Core/SiteAccessAware/TagsService.php @@ -193,9 +193,9 @@ public function hideTag(Tag $tag): void $this->innerService->hideTag($tag); } - public function unhideTag(Tag $tag): void + public function revealTag(Tag $tag): void { - $this->innerService->unhideTag($tag); + $this->innerService->revealTag($tag); } public function sudo(callable $callback, ?TagsServiceInterface $outerTagsService = null): mixed diff --git a/bundle/Resources/config/policies.yaml b/bundle/Resources/config/policies.yaml index 085b07c6..991cac7f 100644 --- a/bundle/Resources/config/policies.yaml +++ b/bundle/Resources/config/policies.yaml @@ -10,6 +10,6 @@ tags: makesynonym: ~ merge: ~ hide: ~ - unhide: ~ + reveal: ~ hidesynonym: ~ - unhidesynonym: ~ + revealsynonym: ~ diff --git a/bundle/Resources/config/routing/admin/tag.yaml b/bundle/Resources/config/routing/admin/tag.yaml index eb1901c1..416be269 100644 --- a/bundle/Resources/config/routing/admin/tag.yaml +++ b/bundle/Resources/config/routing/admin/tag.yaml @@ -43,9 +43,9 @@ netgen_tags_admin_tag_hide_tags: controller: netgen_tags.admin.controller.tag:hideTagsAction methods: [GET, POST] -netgen_tags_admin_tag_unhide_tags: - path: /unhide/{parentId} - controller: netgen_tags.admin.controller.tag:unhideTagsAction +netgen_tags_admin_tag_reveal_tags: + path: /reveal/{parentId} + controller: netgen_tags.admin.controller.tag:revealTagsAction methods: [GET, POST] netgen_tags_admin_tag_update_select: @@ -88,7 +88,7 @@ netgen_tags_admin_tag_hide: controller: netgen_tags.admin.controller.tag:hideAction methods: [GET, POST] -netgen_tags_admin_tag_unhide: - path: /{tagId}/unhide - controller: netgen_tags.admin.controller.tag:unhideAction +netgen_tags_admin_tag_reveal: + path: /{tagId}/reveal + controller: netgen_tags.admin.controller.tag:revealAction methods: [GET, POST] diff --git a/bundle/Resources/public/admin/js/app.js b/bundle/Resources/public/admin/js/app.js index 06695062..cafb7bd8 100644 --- a/bundle/Resources/public/admin/js/app.js +++ b/bundle/Resources/public/admin/js/app.js @@ -378,20 +378,20 @@ function ngTagsInit(jQuery){ if (name === 'Tags') { var $hideButton = $('button[name="HideTagsAction"]'); - var $unhideButton = $('button[name="UnhideTagsAction"]'); + var $revealButton = $('button[name="RevealTagsAction"]'); var hasHidden = false; - var hasUnhidden = false; + var hasRevealed = false; $checkedBoxes.each(function() { var isHidden = $(this).closest('tr').find('td:eq(5)').text().trim() === '1'; - isHidden ? hasHidden = true : hasUnhidden = true; + isHidden ? hasHidden = true : hasRevealed = true; - if (hasHidden && hasUnhidden) return false; + if (hasHidden && hasRevealed) return false; }); $hideButton.prop('disabled', hasHidden || !$checkedBoxes.length); - $unhideButton.prop('disabled', hasUnhidden || !$checkedBoxes.length); + $revealButton.prop('disabled', hasRevealed || !$checkedBoxes.length); } }); } diff --git a/bundle/Resources/translations/netgen_tags_admin.en.yml b/bundle/Resources/translations/netgen_tags_admin.en.yml index e987309d..9eada6b0 100644 --- a/bundle/Resources/translations/netgen_tags_admin.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin.en.yml @@ -74,7 +74,7 @@ tag.add_synonym.title: 'Add synonym' tag.convert.title: 'Convert to synonym' tag.hide.title: 'Hide tag' -tag.unhide.title: 'Unhide tag' +tag.reveal.title: 'Reveal tag' tag.move_tags.title: 'Move tags' tag.move_tags.message: 'Are you sure you want to move the selected tags?' @@ -96,7 +96,7 @@ tag.button.move_selected: 'Move selected tags' tag.button.copy_selected: 'Copy selected tags' tag.button.delete_selected: 'Remove selected tags' tag.button.hide_selected: 'Hide selected tags' -tag.button.unhide_selected: 'Unhide selected tags' +tag.button.reveal_selected: 'Reveal selected tags' tag.button.continue: 'Continue' tag.tree.top_level_tags: 'Top level tags' diff --git a/bundle/Resources/translations/netgen_tags_admin.fr.yml b/bundle/Resources/translations/netgen_tags_admin.fr.yml index 3f8ad53f..b68542bd 100644 --- a/bundle/Resources/translations/netgen_tags_admin.fr.yml +++ b/bundle/Resources/translations/netgen_tags_admin.fr.yml @@ -63,7 +63,7 @@ tag.add_synonym.title: 'Ajouter un synonyme' tag.convert.title: 'Convertir en synonyme' tag.hide.title: 'Cacher le tag' -tag.unhide.title: 'Désactiver le tag' +tag.reveal.title: 'Désactiver le tag' tag.move_tags.title: 'Déplacer les tags' tag.move_tags.message: 'Êtes-vous sûr de vouloir déplacer les tags sélectionnés ?' @@ -85,7 +85,7 @@ tag.button.move_selected: 'Déplacer les tags sélectionnées' tag.button.copy_selected: 'Copier les tags sélectionnés' tag.button.delete_selected: 'Supprimer les tags sélectionnés' tag.button.hide_selected: 'Masquer les tags sélectionnés' -tag.button.unhide_selected: 'Désactiver les balises sélectionnées' +tag.button.reveal_selected: 'Désactiver les balises sélectionnées' tag.button.continue: 'Continuer' tag.tree.top_level_tags: 'Tags de premier niveau' diff --git a/bundle/Resources/translations/netgen_tags_admin_flash.en.yml b/bundle/Resources/translations/netgen_tags_admin_flash.en.yml index bd98a531..4461e7ab 100644 --- a/bundle/Resources/translations/netgen_tags_admin_flash.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin_flash.en.yml @@ -13,9 +13,9 @@ success.tags_moved: 'Tags have been moved successfully' success.tags_copied: 'Tags have been copied successfully' success.tags_deleted: 'Tags have been deleted successfully' success.tags_hidden: 'Tags have been hidden successfully' -success.tags_unhidden: 'Tags have been unhidden successfully' +success.tags_reveal: 'Tags have been revealed successfully' success.translation_removed: 'Translation for locale "%locale%" has been successfully removed' success.main_translation_set: 'Translation for locale "%locale%" has been set as new main translation' success.always_available_set: 'Always available flag has been successfully updated' success.tag_hidden: 'Tag "%tagKeyword%" has been hidden' -success.tag_unhidden: 'Tag "%tagKeyword%" has been unhidden' +success.tag_reveal: 'Tag "%tagKeyword%" has been revealed' diff --git a/bundle/Resources/views/admin/tag/children.html.twig b/bundle/Resources/views/admin/tag/children.html.twig index 2dc59d0b..4d454f91 100644 --- a/bundle/Resources/views/admin/tag/children.html.twig +++ b/bundle/Resources/views/admin/tag/children.html.twig @@ -6,7 +6,7 @@ {% set can_edit = is_granted('ibexa:tags:edit') %} {% set can_delete = is_granted('ibexa:tags:delete') %} {% set can_hide = is_granted('ibexa:tags:hide') %} -{% set can_unhide = is_granted('ibexa:tags:unhide') %} +{% set can_reveal = is_granted('ibexa:tags:reveal') %}

{{ 'tag.children.title'|trans }} ({{ childrenTags|length }})

@@ -80,8 +80,8 @@ {% endif %} - {% if can_unhide %} - + {% if can_reveal %} + {% endif %} diff --git a/bundle/Resources/views/admin/tag/show.html.twig b/bundle/Resources/views/admin/tag/show.html.twig index 2913ed9b..580d49d8 100644 --- a/bundle/Resources/views/admin/tag/show.html.twig +++ b/bundle/Resources/views/admin/tag/show.html.twig @@ -47,8 +47,8 @@ {% if is_granted('ibexa:tags:hide' ~ (tag.isSynonym ? 'synonym' : '')) and not tag.isHidden %} {{ 'tag.hide.title'|trans }} - {% elseif is_granted('ibexa:tags:unhide' ~ (tag.isSynonym ? 'synonym' : '')) and tag.isHidden %} - {{ 'tag.unhide.title'|trans }} + {% elseif is_granted('ibexa:tags:reveal' ~ (tag.isSynonym ? 'synonym' : '')) and tag.isHidden %} + {{ 'tag.reveal.title'|trans }} {% endif %} diff --git a/bundle/SPI/Persistence/Tags/Handler.php b/bundle/SPI/Persistence/Tags/Handler.php index e63f50d8..525e6261 100644 --- a/bundle/SPI/Persistence/Tags/Handler.php +++ b/bundle/SPI/Persistence/Tags/Handler.php @@ -175,9 +175,9 @@ public function deleteTag(int $tagId): void; public function hideTag(int $tagId): void; /** - * Unhides tag identified by $tagId. + * Reveal tag identified by $tagId. * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ - public function unhideTag(int $tagId): void; + public function revealTag(int $tagId): void; } From 8b20a727def5701cca7d8009ab25b8b6113facee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Mon, 9 Jun 2025 08:41:57 +0200 Subject: [PATCH 21/59] NGSTACK-977 make descendant tags who have one hidden parent stay invisible when revealing a tag --- .../Legacy/Tags/Gateway/DoctrineDatabase.php | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index 226f406d..7d24d947 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -880,12 +880,46 @@ public function revealTag(int $tagId): void $query->execute(); + $query = $this->connection->createQueryBuilder(); + $query + ->select('id') + ->from('eztags') + ->where($query->expr()->eq('is_hidden', '1')) + ->andWhere( + $query->expr()->like('path_string', ':path_string'), + ) + ->setParameter('path_string', '%/' . $tagId . '/%', Types::STRING); + + $hiddenDescendantTags = array_map( + static fn (array $row) => $row['id'], + $query->execute()->fetchAll(FetchMode::ASSOCIATIVE), + ); + + $tagsToRemainInvisible = []; + foreach ($hiddenDescendantTags as $hiddenDescendantTag) { + $query = $this->connection->createQueryBuilder(); + $query + ->select('id') + ->from('eztags') + ->where( + $query->expr()->like('path_string', ':path_string'), + ) + ->setParameter('path_string', '%/' . $hiddenDescendantTag . '/%', Types::STRING); + + foreach ($query->execute()->fetchAll(FetchMode::ASSOCIATIVE) as $row) { + $tagsToRemainInvisible[] = $row['id']; + } + } + $query = $this->connection->createQueryBuilder(); $query ->update('eztags') ->set('is_invisible', '0') ->where( - $query->expr()->like('path_string', ':path_string'), + $query->expr()->and( + $query->expr()->like('path_string', ':path_string'), + $query->expr()->notIn('id', $tagsToRemainInvisible), + ), ) ->setParameter('path_string', '%/' . $tagId . '/%', Types::STRING); From 54ec1e9e6de56c8e324578e794b5285a762bd07b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Mon, 9 Jun 2025 09:15:53 +0200 Subject: [PATCH 22/59] NGSTACK-977 fix logic for revealing a hidden tag --- .../Legacy/Tags/Gateway/DoctrineDatabase.php | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index 7d24d947..c9d37b1f 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -896,18 +896,20 @@ public function revealTag(int $tagId): void ); $tagsToRemainInvisible = []; - foreach ($hiddenDescendantTags as $hiddenDescendantTag) { - $query = $this->connection->createQueryBuilder(); - $query - ->select('id') - ->from('eztags') - ->where( - $query->expr()->like('path_string', ':path_string'), - ) - ->setParameter('path_string', '%/' . $hiddenDescendantTag . '/%', Types::STRING); - - foreach ($query->execute()->fetchAll(FetchMode::ASSOCIATIVE) as $row) { - $tagsToRemainInvisible[] = $row['id']; + if ($hiddenDescendantTags !== []) { + foreach ($hiddenDescendantTags as $hiddenDescendantTag) { + $query = $this->connection->createQueryBuilder(); + $query + ->select('id') + ->from('eztags') + ->where( + $query->expr()->like('path_string', ':path_string'), + ) + ->setParameter('path_string', '%/' . $hiddenDescendantTag . '/%', Types::STRING); + + foreach ($query->execute()->fetchAll(FetchMode::ASSOCIATIVE) as $row) { + $tagsToRemainInvisible[] = $row['id']; + } } } @@ -916,13 +918,16 @@ public function revealTag(int $tagId): void ->update('eztags') ->set('is_invisible', '0') ->where( - $query->expr()->and( - $query->expr()->like('path_string', ':path_string'), - $query->expr()->notIn('id', $tagsToRemainInvisible), - ), + $query->expr()->like('path_string', ':path_string'), ) ->setParameter('path_string', '%/' . $tagId . '/%', Types::STRING); + if ($tagsToRemainInvisible !== []) { + $query->andWhere( + $query->expr()->notIn('id', $tagsToRemainInvisible), + ); + } + $query->execute(); } From a61028b12635190e12daa6361e07b88c1ca34460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Mon, 9 Jun 2025 09:48:56 +0200 Subject: [PATCH 23/59] NGSTACK-977 set 'is_hidden' and 'is_invisible' fields correctly when creating a tag --- .../Legacy/Tags/Gateway/DoctrineDatabase.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index c9d37b1f..1eda541e 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -372,7 +372,14 @@ public function create(CreateStruct $createStruct, ?array $parentTag = null): in )->setValue( 'language_mask', ':language_mask', - )->setParameter('parent_id', $parentTag !== null ? (int) $parentTag['id'] : 0, Types::INTEGER) + )->setValue( + 'is_hidden', + ':is_hidden', + )->setValue( + 'is_invisible', + ':is_invisible', + ) + ->setParameter('parent_id', $parentTag !== null ? (int) $parentTag['id'] : 0, Types::INTEGER) ->setParameter('main_tag_id', 0, Types::INTEGER) ->setParameter('modified', time(), Types::INTEGER) ->setParameter('keyword', $createStruct->keywords[$createStruct->mainLanguageCode], Types::STRING) @@ -392,7 +399,8 @@ public function create(CreateStruct $createStruct, ?array $parentTag = null): in is_bool($createStruct->alwaysAvailable) ? $createStruct->alwaysAvailable : true, ), Types::INTEGER, - ); + )->setParameter('is_hidden', 0, Types::INTEGER) + ->setParameter('is_invisible', $parentTag !== null ? $parentTag['is_invisible'] : 0, Types::INTEGER); $query->execute(); From 45b2f03e1bd231af43ab0d233dc96f23e51c58a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Mon, 9 Jun 2025 11:13:08 +0200 Subject: [PATCH 24/59] NGSTACK-977 update logic for revealing a tag to handle both ancestor and descendant hidden tags --- .../Legacy/Tags/Gateway/DoctrineDatabase.php | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index 1eda541e..67b697d6 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -878,6 +878,26 @@ public function hideTag(int $tagId): void public function revealTag(int $tagId): void { + // check if any ancestor is hidden + $basicTagData = $this->getBasicTagData($tagId); + $pathArray = explode('/', trim($basicTagData['path_string'], '/')); + array_pop($pathArray); + + $shouldRemainInvisible = false; + if ($pathArray !== []) { + $query = $this->connection->createQueryBuilder(); + $query + ->select('COUNT(id)') + ->from('eztags') + ->where($query->expr()->eq('is_hidden', '1')) + ->andWhere($query->expr()->in('id', ':parent_ids')) + ->setParameter('parent_ids', $pathArray, Connection::PARAM_INT_ARRAY); + + $hiddenAncestorsCount = (int) $query->execute()->fetch(FetchMode::COLUMN); + $shouldRemainInvisible = $hiddenAncestorsCount > 0; + } + + // update current tag to not be hidden $query = $this->connection->createQueryBuilder(); $query ->update('eztags') @@ -888,6 +908,7 @@ public function revealTag(int $tagId): void $query->execute(); + // find descendant tags that should remain invisible $query = $this->connection->createQueryBuilder(); $query ->select('id') @@ -921,22 +942,25 @@ public function revealTag(int $tagId): void } } - $query = $this->connection->createQueryBuilder(); - $query - ->update('eztags') - ->set('is_invisible', '0') - ->where( - $query->expr()->like('path_string', ':path_string'), - ) - ->setParameter('path_string', '%/' . $tagId . '/%', Types::STRING); + // if at least one ancestor is hidden, remain invisible + if ($shouldRemainInvisible !== true) { + $query = $this->connection->createQueryBuilder(); + $query + ->update('eztags') + ->set('is_invisible', '0') + ->where( + $query->expr()->like('path_string', ':path_string'), + ) + ->setParameter('path_string', '%/' . $tagId . '/%', Types::STRING); - if ($tagsToRemainInvisible !== []) { - $query->andWhere( - $query->expr()->notIn('id', $tagsToRemainInvisible), - ); - } + if ($tagsToRemainInvisible !== []) { + $query->andWhere( + $query->expr()->notIn('id', $tagsToRemainInvisible), + ); + } - $query->execute(); + $query->execute(); + } } private function createTagIdsQuery(?array $translations = null, bool $useAlwaysAvailable = true): QueryBuilder From e50dfdb069fa38552dc79e7d4edd478e0be7e8e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Mon, 9 Jun 2025 11:19:46 +0200 Subject: [PATCH 25/59] NGSTACK-977 fix a test for creating a tag by adding 'is_invisible' property --- .../Persistence/Legacy/Tags/Gateway/DoctrineDatabaseTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabaseTest.php b/tests/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabaseTest.php index 8d84aff7..5ba1dd37 100644 --- a/tests/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabaseTest.php +++ b/tests/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabaseTest.php @@ -587,6 +587,7 @@ public function testCreate(): void 'id' => 40, 'depth' => 3, 'path_string' => '/8/7/40/', + 'is_invisible' => 0, ], ); From 69672a56b8c4b217246826da40559ecd4fe7a13c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Mon, 9 Jun 2025 12:51:59 +0200 Subject: [PATCH 26/59] NGSTACK-977 add events for hiding and revealing a tag and add tests for it --- .../Events/Tags/BeforeHideTagEvent.php | 18 +++++ .../Events/Tags/BeforeRevealTagEvent.php | 18 +++++ .../Repository/Events/Tags/HideTagEvent.php | 18 +++++ .../Repository/Events/Tags/RevealTagEvent.php | 18 +++++ bundle/Core/Event/TagsService.php | 16 ++++ tests/Core/Event/TagsServiceTest.php | 74 +++++++++++++++++++ 6 files changed, 162 insertions(+) create mode 100644 bundle/API/Repository/Events/Tags/BeforeHideTagEvent.php create mode 100644 bundle/API/Repository/Events/Tags/BeforeRevealTagEvent.php create mode 100644 bundle/API/Repository/Events/Tags/HideTagEvent.php create mode 100644 bundle/API/Repository/Events/Tags/RevealTagEvent.php diff --git a/bundle/API/Repository/Events/Tags/BeforeHideTagEvent.php b/bundle/API/Repository/Events/Tags/BeforeHideTagEvent.php new file mode 100644 index 00000000..a6a90d96 --- /dev/null +++ b/bundle/API/Repository/Events/Tags/BeforeHideTagEvent.php @@ -0,0 +1,18 @@ +tag; + } +} diff --git a/bundle/API/Repository/Events/Tags/BeforeRevealTagEvent.php b/bundle/API/Repository/Events/Tags/BeforeRevealTagEvent.php new file mode 100644 index 00000000..27a00d95 --- /dev/null +++ b/bundle/API/Repository/Events/Tags/BeforeRevealTagEvent.php @@ -0,0 +1,18 @@ +tag; + } +} diff --git a/bundle/API/Repository/Events/Tags/HideTagEvent.php b/bundle/API/Repository/Events/Tags/HideTagEvent.php new file mode 100644 index 00000000..6a82c37a --- /dev/null +++ b/bundle/API/Repository/Events/Tags/HideTagEvent.php @@ -0,0 +1,18 @@ +tag; + } +} diff --git a/bundle/API/Repository/Events/Tags/RevealTagEvent.php b/bundle/API/Repository/Events/Tags/RevealTagEvent.php new file mode 100644 index 00000000..1b710de9 --- /dev/null +++ b/bundle/API/Repository/Events/Tags/RevealTagEvent.php @@ -0,0 +1,18 @@ +tag; + } +} diff --git a/bundle/Core/Event/TagsService.php b/bundle/Core/Event/TagsService.php index 9b0505fd..9edacd4e 100644 --- a/bundle/Core/Event/TagsService.php +++ b/bundle/Core/Event/TagsService.php @@ -228,12 +228,28 @@ public function newTagUpdateStruct(): TagUpdateStruct public function hideTag(Tag $tag): void { + $beforeEvent = new Events\BeforeHideTagEvent($tag); + + if ($this->eventDispatcher->dispatch($beforeEvent)->isPropagationStopped()) { + return; + } + $this->service->hideTag($tag); + + $this->eventDispatcher->dispatch(new Events\HideTagEvent($tag)); } public function revealTag(Tag $tag): void { + $beforeEvent = new Events\BeforeRevealTagEvent($tag); + + if ($this->eventDispatcher->dispatch($beforeEvent)->isPropagationStopped()) { + return; + } + $this->service->revealTag($tag); + + $this->eventDispatcher->dispatch(new Events\RevealTagEvent($tag)); } public function sudo(callable $callback, ?TagsServiceInterface $outerTagsService = null): mixed diff --git a/tests/Core/Event/TagsServiceTest.php b/tests/Core/Event/TagsServiceTest.php index b963176c..9de7a466 100644 --- a/tests/Core/Event/TagsServiceTest.php +++ b/tests/Core/Event/TagsServiceTest.php @@ -751,6 +751,80 @@ public function testNewTagUpdateStruct(): void self::assertCount(0, $tagUpdateStruct->getKeywords()); } + /** + * @covers \Netgen\TagsBundle\Core\Event\TagsService::hideTag + */ + public function testHideTag(): void + { + $tag = new Tag( + [ + 'id' => 42, + 'isHidden' => 0, + 'isInvisible' => 0, + ], + ); + + $this->tagsService + ->expects(self::once()) + ->method('hideTag') + ->with(self::identicalTo($tag)); + + $beforeEvent = new Events\BeforeHideTagEvent($tag); + + $this->eventDispatcher + ->expects(self::at(0)) + ->method('dispatch') + ->with(self::equalTo($beforeEvent)) + ->willReturn($beforeEvent); + + $this->eventDispatcher + ->expects(self::at(1)) + ->method('dispatch') + ->with( + self::equalTo(new Events\HideTagEvent($tag)), + ); + + $eventDispatchingService = $this->getEventDispatchingService(); + $eventDispatchingService->hideTag($tag); + } + + /** + * @covers \Netgen\TagsBundle\Core\Event\TagsService::revealTag + */ + public function testRevealTag(): void + { + $tag = new Tag( + [ + 'id' => 42, + 'isHidden' => 1, + 'isInvisible' => 1, + ], + ); + + $this->tagsService + ->expects(self::once()) + ->method('revealTag') + ->with(self::identicalTo($tag)); + + $beforeEvent = new Events\BeforeRevealTagEvent($tag); + + $this->eventDispatcher + ->expects(self::at(0)) + ->method('dispatch') + ->with(self::equalTo($beforeEvent)) + ->willReturn($beforeEvent); + + $this->eventDispatcher + ->expects(self::at(1)) + ->method('dispatch') + ->with( + self::equalTo(new Events\RevealTagEvent($tag)), + ); + + $eventDispatchingService = $this->getEventDispatchingService(); + $eventDispatchingService->revealTag($tag); + } + /** * @covers \Netgen\TagsBundle\Core\Event\TagsService::sudo */ From 086e95491e474b4618c1844ff39be4078fff076b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Tue, 10 Jun 2025 10:16:55 +0200 Subject: [PATCH 27/59] NGSTACK-977 add 'show_hidden' parameter in the configTreeBuilder and contextualized it --- bundle/DependencyInjection/Configuration.php | 4 ++++ bundle/DependencyInjection/NetgenTagsExtension.php | 2 ++ 2 files changed, 6 insertions(+) diff --git a/bundle/DependencyInjection/Configuration.php b/bundle/DependencyInjection/Configuration.php index dca24605..9a234c40 100644 --- a/bundle/DependencyInjection/Configuration.php +++ b/bundle/DependencyInjection/Configuration.php @@ -155,6 +155,10 @@ public function getConfigTreeBuilder(): TreeBuilder ->defaultValue(25) ->end() ->end() + ->end() + ->booleanNode('show_hidden') + ->info('Whether to show hidden tags or not') + ->defaultTrue() ->end(); return $treeBuilder; diff --git a/bundle/DependencyInjection/NetgenTagsExtension.php b/bundle/DependencyInjection/NetgenTagsExtension.php index b2c59365..3cd07bd7 100644 --- a/bundle/DependencyInjection/NetgenTagsExtension.php +++ b/bundle/DependencyInjection/NetgenTagsExtension.php @@ -121,6 +121,8 @@ static function (array $config, string $scope, ContextualizerInterface $c): void $c->setContextualParameter('admin.tree_limit', $scope, $config['admin']['tree_limit']); $c->setContextualParameter('admin.related_content_limit', $scope, $config['admin']['related_content_limit']); $c->setContextualParameter('field.autocomplete_limit', $scope, $config['field']['autocomplete_limit']); + + $c->setContextualParameter('show_hidden', $scope, $config['show_hidden']); }, ); From 4af3ecd15db43be123c07531a1b36306763395ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Tue, 10 Jun 2025 10:21:24 +0200 Subject: [PATCH 28/59] NGSTACK-977 inject configResolver into SiteAccessAware/TagsService, add 'show_hidden' argument to necessary functions in the TagsService implementations --- bundle/API/Repository/TagsService.php | 14 +++++------ bundle/Core/Event/TagsService.php | 28 ++++++++++----------- bundle/Core/Repository/TagsService.php | 23 ++++++++++------- bundle/Core/SiteAccessAware/TagsService.php | 28 +++++++++++++++------ bundle/Resources/config/papi.yaml | 1 + 5 files changed, 56 insertions(+), 38 deletions(-) diff --git a/bundle/API/Repository/TagsService.php b/bundle/API/Repository/TagsService.php index a16ebf8b..d4352301 100644 --- a/bundle/API/Repository/TagsService.php +++ b/bundle/API/Repository/TagsService.php @@ -76,7 +76,7 @@ public function loadTagByUrl(string $url, array $languages): Tag; * * @return \Netgen\TagsBundle\API\Repository\Values\Tags\TagList */ - public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true): TagList; + public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList; /** * Returns the number of children of a tag object. @@ -89,7 +89,7 @@ public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = * * @return int */ - public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true): int; + public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; /** * Loads tags by specified keyword. @@ -104,7 +104,7 @@ public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, * * @return \Netgen\TagsBundle\API\Repository\Values\Tags\TagList */ - public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): TagList; + public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): TagList; /** * Returns the number of tags by specified keyword. @@ -117,7 +117,7 @@ public function loadTagsByKeyword(string $keyword, string $language, bool $useAl * * @return int */ - public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true): int; + public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; /** * Search for tags. @@ -132,7 +132,7 @@ public function getTagsByKeywordCount(string $keyword, string $language, bool $u * * @return \Netgen\TagsBundle\API\Repository\Values\Tags\SearchResult */ - public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): SearchResult; + public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult; /** * Loads synonyms of a tag object. @@ -148,7 +148,7 @@ public function searchTags(string $searchString, string $language, bool $useAlwa * * @return \Netgen\TagsBundle\API\Repository\Values\Tags\TagList */ - public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true): TagList; + public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList; /** * Returns the number of synonyms of a tag object. @@ -162,7 +162,7 @@ public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?arr * * @return int */ - public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true): int; + public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; /** * Loads content related to $tag. diff --git a/bundle/Core/Event/TagsService.php b/bundle/Core/Event/TagsService.php index 9edacd4e..66709881 100644 --- a/bundle/Core/Event/TagsService.php +++ b/bundle/Core/Event/TagsService.php @@ -38,39 +38,39 @@ public function loadTagByUrl(string $url, array $languages): Tag return $this->service->loadTagByUrl($url, $languages); } - public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true): TagList + public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList { - return $this->service->loadTagChildren($tag, $offset, $limit, $languages, $useAlwaysAvailable); + return $this->service->loadTagChildren($tag, $offset, $limit, $languages, $useAlwaysAvailable, $showHidden); } - public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true): int + public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { - return $this->service->getTagChildrenCount($tag, $languages, $useAlwaysAvailable); + return $this->service->getTagChildrenCount($tag, $languages, $useAlwaysAvailable, $showHidden); } - public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): TagList + public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): TagList { - return $this->service->loadTagsByKeyword($keyword, $language, $useAlwaysAvailable, $offset, $limit); + return $this->service->loadTagsByKeyword($keyword, $language, $useAlwaysAvailable, $offset, $limit, $showHidden); } - public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true): int + public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { - return $this->service->getTagsByKeywordCount($keyword, $language, $useAlwaysAvailable); + return $this->service->getTagsByKeywordCount($keyword, $language, $useAlwaysAvailable, $showHidden); } - public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): SearchResult + public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult { - return $this->service->searchTags($searchString, $language, $useAlwaysAvailable, $offset, $limit); + return $this->service->searchTags($searchString, $language, $useAlwaysAvailable, $offset, $limit, $showHidden); } - public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true): TagList + public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList { - return $this->service->loadTagSynonyms($tag, $offset, $limit, $languages, $useAlwaysAvailable); + return $this->service->loadTagSynonyms($tag, $offset, $limit, $languages, $useAlwaysAvailable, $showHidden); } - public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true): int + public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { - return $this->service->getTagSynonymCount($tag, $languages, $useAlwaysAvailable); + return $this->service->getTagSynonymCount($tag, $languages, $useAlwaysAvailable, $showHidden); } public function getRelatedContent(Tag $tag, int $offset = 0, int $limit = -1, bool $returnContentInfo = true, array $additionalCriteria = [], array $sortClauses = []): array diff --git a/bundle/Core/Repository/TagsService.php b/bundle/Core/Repository/TagsService.php index fb41da59..eec3056a 100644 --- a/bundle/Core/Repository/TagsService.php +++ b/bundle/Core/Repository/TagsService.php @@ -152,7 +152,7 @@ public function loadTagByUrl(string $url, array $languages): Tag return $this->mapper->buildTagDomainObject($spiTag, $languages); } - public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true): TagList + public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); @@ -164,6 +164,7 @@ public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = $limit, $languages, $useAlwaysAvailable, + $showHidden, ); $tags = []; @@ -174,7 +175,7 @@ public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = return new TagList($tags); } - public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true): int + public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); @@ -184,16 +185,17 @@ public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, $tag?->id ?? 0, $languages, $useAlwaysAvailable, + $showHidden, ); } - public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): TagList + public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): TagList { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); } - $spiTags = $this->tagsHandler->loadTagsByKeyword($keyword, $language, $useAlwaysAvailable, $offset, $limit); + $spiTags = $this->tagsHandler->loadTagsByKeyword($keyword, $language, $useAlwaysAvailable, $offset, $limit, $showHidden); $tags = []; foreach ($spiTags as $spiTag) { @@ -203,16 +205,16 @@ public function loadTagsByKeyword(string $keyword, string $language, bool $useAl return new TagList($tags); } - public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true): int + public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); } - return $this->tagsHandler->getTagsByKeywordCount($keyword, $language, $useAlwaysAvailable); + return $this->tagsHandler->getTagsByKeywordCount($keyword, $language, $useAlwaysAvailable, $showHidden); } - public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): SearchResult + public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); @@ -224,6 +226,7 @@ public function searchTags(string $searchString, string $language, bool $useAlwa $useAlwaysAvailable, $offset, $limit, + $showHidden, ); $tags = []; @@ -239,7 +242,7 @@ public function searchTags(string $searchString, string $language, bool $useAlwa ); } - public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true): TagList + public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); @@ -255,6 +258,7 @@ public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?arr $limit, $languages, $useAlwaysAvailable, + $showHidden, ); $tags = []; @@ -265,7 +269,7 @@ public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?arr return new TagList($tags); } - public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true): int + public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); @@ -279,6 +283,7 @@ public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $use $tag->id, $languages, $useAlwaysAvailable, + $showHidden, ); } diff --git a/bundle/Core/SiteAccessAware/TagsService.php b/bundle/Core/SiteAccessAware/TagsService.php index 5362195d..f03ec529 100644 --- a/bundle/Core/SiteAccessAware/TagsService.php +++ b/bundle/Core/SiteAccessAware/TagsService.php @@ -5,6 +5,7 @@ namespace Netgen\TagsBundle\Core\SiteAccessAware; use Ibexa\Contracts\Core\Repository\LanguageResolver; +use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface; use Netgen\TagsBundle\API\Repository\TagsService as TagsServiceInterface; use Netgen\TagsBundle\API\Repository\Values\Tags\SearchResult; use Netgen\TagsBundle\API\Repository\Values\Tags\SynonymCreateStruct; @@ -15,7 +16,11 @@ final class TagsService implements TagsServiceInterface { - public function __construct(private TagsServiceInterface $innerService, private LanguageResolver $languageResolver) {} + public function __construct( + private TagsServiceInterface $innerService, + private LanguageResolver $languageResolver, + private ConfigResolverInterface $configResolver, + ) {} public function loadTag(int $tagId, ?array $languages = null, bool $useAlwaysAvailable = true): Tag { @@ -52,7 +57,7 @@ public function loadTagByUrl(string $url, array $languages): Tag ); } - public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true): TagList + public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList { return $this->innerService->loadTagChildren( $tag, @@ -60,19 +65,21 @@ public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = $limit, $this->languageResolver->getPrioritizedLanguages($languages), $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), + $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), ); } - public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true): int + public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { return $this->innerService->getTagChildrenCount( $tag, $this->languageResolver->getPrioritizedLanguages($languages), $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), + $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), ); } - public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): TagList + public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): TagList { return $this->innerService->loadTagsByKeyword( $keyword, @@ -80,19 +87,21 @@ public function loadTagsByKeyword(string $keyword, string $language, bool $useAl $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), $offset, $limit, + $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), ); } - public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true): int + public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { return $this->innerService->getTagsByKeywordCount( $keyword, $language, $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), + $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), ); } - public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): SearchResult + public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult { return $this->innerService->searchTags( $searchString, @@ -100,10 +109,11 @@ public function searchTags(string $searchString, string $language, bool $useAlwa $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), $offset, $limit, + $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), ); } - public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true): TagList + public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList { return $this->innerService->loadTagSynonyms( $tag, @@ -111,15 +121,17 @@ public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?arr $limit, $this->languageResolver->getPrioritizedLanguages($languages), $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), + $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), ); } - public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true): int + public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { return $this->innerService->getTagSynonymCount( $tag, $this->languageResolver->getPrioritizedLanguages($languages), $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), + $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), ); } diff --git a/bundle/Resources/config/papi.yaml b/bundle/Resources/config/papi.yaml index 9c5d41b6..8541dbc1 100644 --- a/bundle/Resources/config/papi.yaml +++ b/bundle/Resources/config/papi.yaml @@ -17,6 +17,7 @@ services: arguments: - "@netgen_tags.event.service.tags" - "@ibexa.helper.language_resolver" + - "@ibexa.config.resolver" netgen_tags.api.service.tags.mapper: class: Netgen\TagsBundle\Core\Repository\TagsMapper From 0f8c7dd4b1233019e9bb0c8e9e54c26aab94dd3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Tue, 10 Jun 2025 10:23:48 +0200 Subject: [PATCH 29/59] NGSTACK-977 add 'show_hidden' argument to necessary functions in the SPI/Persistence layer and pass it on down to the Gateway --- bundle/Core/Persistence/Cache/TagsHandler.php | 28 ++++++++--------- .../Core/Persistence/Legacy/Tags/Handler.php | 30 +++++++++---------- bundle/SPI/Persistence/Tags/Handler.php | 14 ++++----- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/bundle/Core/Persistence/Cache/TagsHandler.php b/bundle/Core/Persistence/Cache/TagsHandler.php index ca24270b..5d065c6d 100644 --- a/bundle/Core/Persistence/Cache/TagsHandler.php +++ b/bundle/Core/Persistence/Cache/TagsHandler.php @@ -155,42 +155,42 @@ public function loadTagByKeywordAndParentId(string $keyword, int $parentTagId, ? return $this->tagsHandler->loadTagByKeywordAndParentId($keyword, $parentTagId, $translations, $useAlwaysAvailable); } - public function loadChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true): array + public function loadChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array { $this->logger->logCall(__METHOD__, ['tag' => $tagId, 'translations' => $translations, 'useAlwaysAvailable' => $useAlwaysAvailable]); - return $this->tagsHandler->loadChildren($tagId, $offset, $limit, $translations, $useAlwaysAvailable); + return $this->tagsHandler->loadChildren($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHidden); } - public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true): int + public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { $this->logger->logCall(__METHOD__, ['tag' => $tagId, 'translations' => $translations, 'useAlwaysAvailable' => $useAlwaysAvailable]); - return $this->tagsHandler->getChildrenCount($tagId, $translations, $useAlwaysAvailable); + return $this->tagsHandler->getChildrenCount($tagId, $translations, $useAlwaysAvailable, $showHidden); } - public function loadTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): array + public function loadTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): array { $this->logger->logCall(__METHOD__, ['keyword' => $keyword, 'translation' => $translation, 'useAlwaysAvailable' => $useAlwaysAvailable]); - return $this->tagsHandler->loadTagsByKeyword($keyword, $translation, $useAlwaysAvailable, $offset, $limit); + return $this->tagsHandler->loadTagsByKeyword($keyword, $translation, $useAlwaysAvailable, $offset, $limit, $showHidden); } - public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true): int + public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { $this->logger->logCall(__METHOD__, ['keyword' => $keyword, 'translation' => $translation, 'useAlwaysAvailable' => $useAlwaysAvailable]); - return $this->tagsHandler->getTagsByKeywordCount($keyword, $translation, $useAlwaysAvailable); + return $this->tagsHandler->getTagsByKeywordCount($keyword, $translation, $useAlwaysAvailable, $showHidden); } - public function searchTags(string $searchString, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): SearchResult + public function searchTags(string $searchString, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult { $this->logger->logCall(__METHOD__, ['searchString' => $searchString, 'translation' => $translation, 'useAlwaysAvailable' => $useAlwaysAvailable]); - return $this->tagsHandler->searchTags($searchString, $translation, $useAlwaysAvailable, $offset, $limit); + return $this->tagsHandler->searchTags($searchString, $translation, $useAlwaysAvailable, $offset, $limit, $showHidden); } - public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true): array + public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array { // Method caches all synonyms in cache and only uses offset / limit to slice the cached result $translationsKey = count($translations ?? []) === 0 @@ -208,7 +208,7 @@ public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?arra $this->logger->logCall(__METHOD__, ['tag' => $tagId, 'translations' => $translations, 'useAlwaysAvailable' => $useAlwaysAvailable]); $tagInfo = $this->loadTagInfo($tagId); - $synonyms = $this->tagsHandler->loadSynonyms($tagId, 0, -1, $translations, $useAlwaysAvailable); + $synonyms = $this->tagsHandler->loadSynonyms($tagId, 0, -1, $translations, $useAlwaysAvailable, $showHidden); $cacheItem->set($synonyms); $cacheTags = [$this->getCacheTags($tagInfo->id, $tagInfo->pathString)]; @@ -221,11 +221,11 @@ public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?arra return array_slice($synonyms, $offset, $limit > -1 ? $limit : null); } - public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true): int + public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { $this->logger->logCall(__METHOD__, ['tag' => $tagId, 'translations' => $translations, 'useAlwaysAvailable' => $useAlwaysAvailable]); - return $this->tagsHandler->getSynonymCount($tagId, $translations, $useAlwaysAvailable); + return $this->tagsHandler->getSynonymCount($tagId, $translations, $useAlwaysAvailable, $showHidden); } public function create(CreateStruct $createStruct): Tag diff --git a/bundle/Core/Persistence/Legacy/Tags/Handler.php b/bundle/Core/Persistence/Legacy/Tags/Handler.php index c2f4f616..5cc3cc5d 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Handler.php +++ b/bundle/Core/Persistence/Legacy/Tags/Handler.php @@ -89,34 +89,34 @@ public function loadTagByKeywordAndParentId(string $keyword, int $parentTagId, ? return reset($tag); } - public function loadChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true): array + public function loadChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array { - $tags = $this->gateway->getChildren($tagId, $offset, $limit, $translations, $useAlwaysAvailable); + $tags = $this->gateway->getChildren($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHidden); return $this->mapper->extractTagListFromRows($tags); } - public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true): int + public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { - return $this->gateway->getChildrenCount($tagId, $translations, $useAlwaysAvailable); + return $this->gateway->getChildrenCount($tagId, $translations, $useAlwaysAvailable, $showHidden); } - public function loadTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): array + public function loadTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): array { - $tags = $this->gateway->getTagsByKeyword($keyword, $translation, $useAlwaysAvailable, true, $offset, $limit); + $tags = $this->gateway->getTagsByKeyword($keyword, $translation, $useAlwaysAvailable, true, $offset, $limit, $showHidden); return $this->mapper->extractTagListFromRows($tags); } - public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true): int + public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { - return $this->gateway->getTagsByKeywordCount($keyword, $translation, $useAlwaysAvailable); + return $this->gateway->getTagsByKeywordCount($keyword, $translation, $useAlwaysAvailable, $showHidden); } - public function searchTags(string $searchString, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): SearchResult + public function searchTags(string $searchString, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult { - $tags = $this->gateway->getTagsByKeyword($searchString, $translation, $useAlwaysAvailable, false, $offset, $limit); - $totalCount = $this->gateway->getTagsByKeywordCount($searchString, $translation, $useAlwaysAvailable, false); + $tags = $this->gateway->getTagsByKeyword($searchString, $translation, $useAlwaysAvailable, false, $offset, $limit, $showHidden); + $totalCount = $this->gateway->getTagsByKeywordCount($searchString, $translation, $useAlwaysAvailable, $showHidden, false); return new SearchResult( [ @@ -126,16 +126,16 @@ public function searchTags(string $searchString, string $translation, bool $useA ); } - public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true): array + public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array { - $tags = $this->gateway->getSynonyms($tagId, $offset, $limit, $translations, $useAlwaysAvailable); + $tags = $this->gateway->getSynonyms($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHidden); return $this->mapper->extractTagListFromRows($tags); } - public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true): int + public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { - return $this->gateway->getSynonymCount($tagId, $translations, $useAlwaysAvailable); + return $this->gateway->getSynonymCount($tagId, $translations, $useAlwaysAvailable, $showHidden); } public function create(CreateStruct $createStruct): Tag diff --git a/bundle/SPI/Persistence/Tags/Handler.php b/bundle/SPI/Persistence/Tags/Handler.php index 525e6261..1c717f0a 100644 --- a/bundle/SPI/Persistence/Tags/Handler.php +++ b/bundle/SPI/Persistence/Tags/Handler.php @@ -63,33 +63,33 @@ public function loadTagByKeywordAndParentId(string $keyword, int $parentTagId, ? * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ - public function loadChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true): array; + public function loadChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array; /** * Returns the number of children of a tag identified by $tagId. * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ - public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true): int; + public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; /** * Loads tags with specified $keyword. * * If $limit = -1 all tags starting at $offset are returned. */ - public function loadTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): array; + public function loadTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): array; /** * Returns the number of tags with specified $keyword. */ - public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true): int; + public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; /** * Searches for tags. * * If $limit = -1 all tags starting at $offset are returned. */ - public function searchTags(string $searchString, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1): SearchResult; + public function searchTags(string $searchString, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult; /** * Loads the synonyms of a tag identified by $tagId. @@ -98,14 +98,14 @@ public function searchTags(string $searchString, string $translation, bool $useA * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ - public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true): array; + public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array; /** * Returns the number of synonyms of a tag identified by $tagId. * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ - public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true): int; + public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; /** * Creates the new tag. From 75858b832236bda673435fed89fb52f88972cb29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Tue, 10 Jun 2025 10:26:07 +0200 Subject: [PATCH 30/59] NGSTACK-977 add 'show_hidden' argument to necessary functions in the Gateway class and update the logic to handle when 'showHidden' config param is false --- .../Core/Persistence/Legacy/Tags/Gateway.php | 12 ++-- .../Legacy/Tags/Gateway/DoctrineDatabase.php | 72 +++++++++++++++++-- .../Tags/Gateway/ExceptionConversion.php | 24 +++---- 3 files changed, 84 insertions(+), 24 deletions(-) diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway.php b/bundle/Core/Persistence/Legacy/Tags/Gateway.php index 51d76678..02865c6e 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway.php @@ -40,36 +40,36 @@ abstract public function getFullTagDataByKeywordAndParentId(string $keyword, int * * If $limit = -1 all children starting at $offset are returned. */ - abstract public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true): array; + abstract public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array; /** * Returns how many tags exist below tag identified by $tagId. */ - abstract public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true): int; + abstract public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; /** * Returns data for tags identified by given $keyword. * * If $limit = -1 all tags starting at $offset are returned. */ - abstract public function getTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true, int $offset = 0, int $limit = -1): array; + abstract public function getTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): array; /** * Returns how many tags exist with $keyword. */ - abstract public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true): int; + abstract public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHidden = null, bool $exactMatch = true): int; /** * Returns data for synonyms of the tag identified by given $tagId. * * If $limit = -1 all synonyms starting at $offset are returned. */ - abstract public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true): array; + abstract public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array; /** * Returns how many synonyms exist for a tag identified by $tagId. */ - abstract public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true): int; + abstract public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; /** * Moves the synonym identified by $synonymId to tag identified by $mainTagData. diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index 67b697d6..9c3cde5e 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -126,9 +126,16 @@ public function getFullTagDataByKeywordAndParentId(string $keyword, int $parentI return $query->execute()->fetchAll(FetchMode::ASSOCIATIVE); } - public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true): array + public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array { $tagIdsQuery = $this->createTagIdsQuery($translations, $useAlwaysAvailable); + + if ($showHidden !== null && $showHidden === false) { + $tagIdsQuery->andWhere( + $tagIdsQuery->expr()->neq('is_hidden', '1'), + ); + } + $tagIdsQuery->andWhere( $tagIdsQuery->expr()->andX( $tagIdsQuery->expr()->eq( @@ -154,6 +161,13 @@ public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array } $query = $this->createTagFindQuery($translations, $useAlwaysAvailable); + + if ($showHidden !== null && $showHidden === false) { + $query->andWhere( + $query->expr()->neq('is_hidden', '1'), + ); + } + $query->andWhere( $query->expr()->in( 'eztags.id', @@ -166,9 +180,16 @@ public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array return $query->execute()->fetchAll(FetchMode::ASSOCIATIVE); } - public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true): int + public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { $query = $this->createTagCountQuery($translations, $useAlwaysAvailable); + + if ($showHidden !== null && $showHidden === false) { + $query->andWhere( + $query->expr()->neq('is_hidden', '1'), + ); + } + $query->andWhere( $query->expr()->andX( $query->expr()->eq( @@ -184,11 +205,17 @@ public function getChildrenCount(int $tagId, ?array $translations = null, bool $ return (int) $rows[0]['count']; } - public function getTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true, int $offset = 0, int $limit = -1): array + public function getTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): array { $databasePlatform = $this->connection->getDatabasePlatform(); $tagIdsQuery = $this->createTagIdsQuery([$translation], $useAlwaysAvailable); + if ($showHidden !== null && $showHidden === false) { + $tagIdsQuery->andWhere( + $tagIdsQuery->expr()->neq('is_hidden', '1'), + ); + } + $tagIdsQuery->andWhere( $exactMatch ? $tagIdsQuery->expr()->eq( @@ -222,6 +249,12 @@ public function getTagsByKeyword(string $keyword, string $translation, bool $use $query = $this->createTagFindQuery([$translation], $useAlwaysAvailable); + if ($showHidden !== null && $showHidden === false) { + $query->andWhere( + $query->expr()->neq('is_hidden', '1'), + ); + } + $query->andWhere( $query->expr()->in( 'eztags.id', @@ -234,11 +267,17 @@ public function getTagsByKeyword(string $keyword, string $translation, bool $use return $query->execute()->fetchAll(FetchMode::ASSOCIATIVE); } - public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true): int + public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHidden = null, bool $exactMatch = true): int { $databasePlatform = $this->connection->getDatabasePlatform(); $query = $this->createTagCountQuery([$translation, $useAlwaysAvailable]); + if ($showHidden !== null && $showHidden === false) { + $query->andWhere( + $query->expr()->neq('is_hidden', '1'), + ); + } + $query->andWhere( $exactMatch ? $query->expr()->eq( @@ -260,9 +299,16 @@ public function getTagsByKeywordCount(string $keyword, string $translation, bool return (int) $rows[0]['count']; } - public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true): array + public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array { $tagIdsQuery = $this->createTagIdsQuery($translations, $useAlwaysAvailable); + + if ($showHidden !== null && $showHidden === false) { + $tagIdsQuery->andWhere( + $tagIdsQuery->expr()->neq('is_hidden', '1'), + ); + } + $tagIdsQuery->andWhere( $tagIdsQuery->expr()->eq( 'eztags.main_tag_id', @@ -284,6 +330,13 @@ public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array } $query = $this->createTagFindQuery($translations, $useAlwaysAvailable); + + if ($showHidden !== null && $showHidden === false) { + $query->andWhere( + $query->expr()->neq('is_hidden', '1'), + ); + } + $query->andWhere( $query->expr()->in( 'eztags.id', @@ -294,9 +347,16 @@ public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array return $query->execute()->fetchAll(FetchMode::ASSOCIATIVE); } - public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true): int + public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { $query = $this->createTagCountQuery($translations, $useAlwaysAvailable); + + if ($showHidden !== null && $showHidden === false) { + $query->andWhere( + $query->expr()->neq('is_hidden', '1'), + ); + } + $query->andWhere( $query->expr()->eq( 'eztags.main_tag_id', diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php index 9ad5dfe4..a4c94c7f 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php @@ -71,10 +71,10 @@ public function getFullTagDataByKeywordAndParentId(string $keyword, int $parentI } } - public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true): array + public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array { try { - return $this->innerGateway->getChildren($tagId, $offset, $limit, $translations, $useAlwaysAvailable); + return $this->innerGateway->getChildren($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHidden); } catch (DBALException $e) { throw new RuntimeException('Database error', 0, $e); } catch (PDOException $e) { @@ -82,10 +82,10 @@ public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array } } - public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true): int + public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { try { - return $this->innerGateway->getChildrenCount($tagId, $translations, $useAlwaysAvailable); + return $this->innerGateway->getChildrenCount($tagId, $translations, $useAlwaysAvailable, $showHidden); } catch (DBALException $e) { throw new RuntimeException('Database error', 0, $e); } catch (PDOException $e) { @@ -93,10 +93,10 @@ public function getChildrenCount(int $tagId, ?array $translations = null, bool $ } } - public function getTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true, int $offset = 0, int $limit = -1): array + public function getTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): array { try { - return $this->innerGateway->getTagsByKeyword($keyword, $translation, $useAlwaysAvailable, $exactMatch, $offset, $limit); + return $this->innerGateway->getTagsByKeyword($keyword, $translation, $useAlwaysAvailable, $exactMatch, $offset, $limit, $showHidden); } catch (DBALException $e) { throw new RuntimeException('Database error', 0, $e); } catch (PDOException $e) { @@ -104,10 +104,10 @@ public function getTagsByKeyword(string $keyword, string $translation, bool $use } } - public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true): int + public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHidden = null, bool $exactMatch = true): int { try { - return $this->innerGateway->getTagsByKeywordCount($keyword, $translation, $useAlwaysAvailable, $exactMatch); + return $this->innerGateway->getTagsByKeywordCount($keyword, $translation, $useAlwaysAvailable, $showHidden, $exactMatch); } catch (DBALException $e) { throw new RuntimeException('Database error', 0, $e); } catch (PDOException $e) { @@ -115,10 +115,10 @@ public function getTagsByKeywordCount(string $keyword, string $translation, bool } } - public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true): array + public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array { try { - return $this->innerGateway->getSynonyms($tagId, $offset, $limit, $translations, $useAlwaysAvailable); + return $this->innerGateway->getSynonyms($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHidden); } catch (DBALException $e) { throw new RuntimeException('Database error', 0, $e); } catch (PDOException $e) { @@ -126,10 +126,10 @@ public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array } } - public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true): int + public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int { try { - return $this->innerGateway->getSynonymCount($tagId, $translations, $useAlwaysAvailable); + return $this->innerGateway->getSynonymCount($tagId, $translations, $useAlwaysAvailable, $showHidden); } catch (DBALException $e) { throw new RuntimeException('Database error', 0, $e); } catch (PDOException $e) { From d99a9d49d6bb0b89d4f5c022bbbf7edaf88f9143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Tue, 10 Jun 2025 10:51:28 +0200 Subject: [PATCH 31/59] NGSTACK-977 update PHPDoc for hide and reveal methods and add ' (hidden)' text next to synonym name if the synonym is hidden --- bundle/API/Repository/TagsService.php | 4 ++++ bundle/Resources/views/admin/tag/tabs/synonyms.html.twig | 9 ++++++++- bundle/SPI/Persistence/Tags/Handler.php | 4 ++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/bundle/API/Repository/TagsService.php b/bundle/API/Repository/TagsService.php index d4352301..2676abd3 100644 --- a/bundle/API/Repository/TagsService.php +++ b/bundle/API/Repository/TagsService.php @@ -289,6 +289,8 @@ public function newTagUpdateStruct(): TagUpdateStruct; /** * Hides $tag. * + * If $tag is a synonym, only the synonym is hidden. + * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException If the current user is not allowed to hide this tag * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ @@ -297,6 +299,8 @@ public function hideTag(Tag $tag): void; /** * Reveal $tag. * + * If $tag is a synonym, only the synonym is revealed. + * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException If the current user is not allowed to reveal this tag * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ diff --git a/bundle/Resources/views/admin/tag/tabs/synonyms.html.twig b/bundle/Resources/views/admin/tag/tabs/synonyms.html.twig index 190e65dc..2b906d1b 100644 --- a/bundle/Resources/views/admin/tag/tabs/synonyms.html.twig +++ b/bundle/Resources/views/admin/tag/tabs/synonyms.html.twig @@ -13,7 +13,14 @@ {% for synonym in synonyms %} {{ synonym.id }} - {{ synonym.keyword }} + + + {{ synonym.keyword }} + {% if synonym.isHidden %} + ({{ 'tag.hidden'|trans|lower }}) + {% endif %} + + {{ synonym.modificationDate|date }} {% endfor %} diff --git a/bundle/SPI/Persistence/Tags/Handler.php b/bundle/SPI/Persistence/Tags/Handler.php index 1c717f0a..4fbee896 100644 --- a/bundle/SPI/Persistence/Tags/Handler.php +++ b/bundle/SPI/Persistence/Tags/Handler.php @@ -170,6 +170,8 @@ public function deleteTag(int $tagId): void; /** * Hides tag identified by $tagId. * + * If $tagId is a synonym, only the synonym is hidden. + * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ public function hideTag(int $tagId): void; @@ -177,6 +179,8 @@ public function hideTag(int $tagId): void; /** * Reveal tag identified by $tagId. * + * If $tagId is a synonym, only the synonym is revealed. + * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ public function revealTag(int $tagId): void; From d09d660632b857192932eac0b9d0f2d6e7c058cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Tue, 10 Jun 2025 11:03:35 +0200 Subject: [PATCH 32/59] NGSTACK-977 add ' (hidden)' next to tag keyword in the TagTreeData if the tag is hidden --- bundle/Controller/Admin/TreeController.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/bundle/Controller/Admin/TreeController.php b/bundle/Controller/Admin/TreeController.php index 7b6d6827..ca1f182e 100644 --- a/bundle/Controller/Admin/TreeController.php +++ b/bundle/Controller/Admin/TreeController.php @@ -12,6 +12,7 @@ use Symfony\Contracts\Translation\TranslatorInterface; use function htmlspecialchars; +use function mb_strtolower; use function str_replace; use const ENT_HTML401; @@ -121,10 +122,22 @@ private function getTagTreeData(Tag $tag, bool $isRoot = false): array { $synonymCount = $this->tagsService->getTagSynonymCount($tag); + $text = $this->escape($tag->keyword); + + if ($tag->isHidden) { + $text .= ' (' . mb_strtolower($this->translator->trans('tag.hidden', [], 'netgen_tags_admin')) . ')'; + } elseif ($tag->isInvisible) { + $text .= ' (' . $this->translator->trans('tag.hidden_by_parent', [], 'netgen_tags_admin') . ')'; + } + + if ($synonymCount > 0) { + $text .= ' (+' . $synonymCount . ')'; + } + return [ 'id' => $tag->id, 'parent' => $isRoot ? '#' : $tag->parentTagId, - 'text' => $synonymCount > 0 ? $this->escape($tag->keyword) . ' (+' . $synonymCount . ')' : $this->escape($tag->keyword), + 'text' => $text, 'children' => $this->tagsService->getTagChildrenCount($tag) > 0, 'hidden' => $tag->isHidden, 'invisible' => $tag->isInvisible, From a6d74152c860f470c52b1da964c6625ae55d9e31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Tue, 10 Jun 2025 14:25:23 +0200 Subject: [PATCH 33/59] NGSTACK-977 update DoctrineDatabaseTest and TagsHandlerTest with tests for revealTag() and hideTag() methods --- .../Tags/Gateway/DoctrineDatabaseTest.php | 84 +++++++++++++++++++ .../Legacy/Tags/TagsHandlerTest.php | 56 +++++++++++++ 2 files changed, 140 insertions(+) diff --git a/tests/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabaseTest.php b/tests/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabaseTest.php index 5ba1dd37..748bc0ed 100644 --- a/tests/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabaseTest.php +++ b/tests/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabaseTest.php @@ -823,6 +823,90 @@ public function testDeleteTag(): void ); } + /** + * @covers \Netgen\TagsBundle\Core\Persistence\Legacy\Tags\Gateway\DoctrineDatabase::hideTag + */ + public function testHideTag(): void + { + $this->tagsGateway->hideTag(7); + + $query = $this->connection->createQueryBuilder(); + self::assertQueryResult( + [ + [1], + ], + $query + ->select('is_hidden') + ->from('eztags') + ->where( + $query->expr()->eq('id', ':id'), + ) + ->setParameter('id', 7), + ); + + $query = $this->connection->createQueryBuilder(); + self::assertQueryResult( + [ + [1], + [1], + [1], + [1], + [1], + [1], + [1], + [1], + ], + $query + ->select('is_invisible') + ->from('eztags') + ->where($query->expr()->in('id', [':children_ids'])) + ->setParameter('children_ids', [7, 13, 14, 27, 40, 53, 54, 55], Connection::PARAM_INT_ARRAY), + ); + } + + /** + * @covers \Netgen\TagsBundle\Core\Persistence\Legacy\Tags\Gateway\DoctrineDatabase::revealTag + */ + public function testRevealTag(): void + { + $this->tagsGateway->revealTag(7); + + $query = $this->connection->createQueryBuilder(); + self::assertQueryResult( + [ + [0], + ], + $query + ->select('is_hidden') + ->from('eztags') + ->where( + $query->expr()->eq('id', ':id'), + ) + ->setParameter('id', 7), + ); + + $query = $this->connection->createQueryBuilder(); + self::assertQueryResult( + [ + [0], + [0], + [0], + [0], + [0], + [0], + [0], + [0], + ], + $query + ->select('is_invisible') + ->from('eztags') + ->where( + $query->expr()->in('id', [':children_ids']), + ) + ->setParameter('children_ids', [7, 13, 14, 27, 40, 53, 54, 55], Connection::PARAM_INT_ARRAY), + ); + } + /** * Returns gateway implementation for legacy storage. */ diff --git a/tests/Core/Persistence/Legacy/Tags/TagsHandlerTest.php b/tests/Core/Persistence/Legacy/Tags/TagsHandlerTest.php index cc388a8a..eed3792e 100644 --- a/tests/Core/Persistence/Legacy/Tags/TagsHandlerTest.php +++ b/tests/Core/Persistence/Legacy/Tags/TagsHandlerTest.php @@ -957,6 +957,62 @@ public function testDeleteTag(): void $handler->deleteTag(40); } + /** + * @covers \Netgen\TagsBundle\Core\Persistence\Legacy\Tags\Handler::hideTag + */ + public function testHideTag(): void + { + $handler = $this->getMockedTagsHandler(['loadTagInfo']); + + $handler + ->expects(self::once()) + ->method('loadTagInfo') + ->with(40) + ->willReturn( + new TagInfo( + [ + 'id' => 40, + 'parentTagId' => 21, + ], + ), + ); + + $this->gateway + ->expects(self::once()) + ->method('hideTag') + ->with(40); + + $handler->hideTag(40); + } + + /** + * @covers \Netgen\TagsBundle\Core\Persistence\Legacy\Tags\Handler::revealTag + */ + public function testRevealTag(): void + { + $handler = $this->getMockedTagsHandler(['loadTagInfo']); + + $handler + ->expects(self::once()) + ->method('loadTagInfo') + ->with(40) + ->willReturn( + new TagInfo( + [ + 'id' => 40, + 'parentTagId' => 21, + ], + ), + ); + + $this->gateway + ->expects(self::once()) + ->method('revealTag') + ->with(40); + + $handler->revealTag(40); + } + private function getTagsHandler(): HandlerInterface { $this->gateway = $this->createMock(Gateway::class); From eed05e279dbcd800dd24c468bcb6bc29e21aa00e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Wed, 11 Jun 2025 10:40:28 +0200 Subject: [PATCH 34/59] NGSTACK-977 add 'hide_tag' and 'reveal_tag' data to the TagTree in TreeController --- bundle/Controller/Admin/TreeController.php | 14 ++++++++++++++ .../translations/netgen_tags_admin.en.yml | 2 ++ .../translations/netgen_tags_admin.fr.yml | 4 +++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/bundle/Controller/Admin/TreeController.php b/bundle/Controller/Admin/TreeController.php index ca1f182e..75eda913 100644 --- a/bundle/Controller/Admin/TreeController.php +++ b/bundle/Controller/Admin/TreeController.php @@ -45,6 +45,8 @@ public function __construct( 'merge_tag' => $this->translator->trans('tag.tree.merge_tag', [], 'netgen_tags_admin'), 'convert_tag' => $this->translator->trans('tag.tree.convert_tag', [], 'netgen_tags_admin'), 'add_synonym' => $this->translator->trans('tag.tree.add_synonym', [], 'netgen_tags_admin'), + 'hide_tag' => $this->translator->trans('tag.tree.hide_tag', [], 'netgen_tags_admin'), + 'reveal_tag' => $this->translator->trans('tag.tree.reveal_tag', [], 'netgen_tags_admin'), ]; $this->treeLinks = [ @@ -56,6 +58,8 @@ public function __construct( 'merge_tag' => $this->router->generate('netgen_tags_admin_tag_merge', ['tagId' => ':tagId']), 'convert_tag' => $this->router->generate('netgen_tags_admin_tag_convert', ['tagId' => ':tagId']), 'add_synonym' => $this->router->generate('netgen_tags_admin_synonym_add_select', ['mainTagId' => ':mainTagId']), + 'hide_tag' => $this->router->generate('netgen_tags_admin_tag_hide', ['tagId' => ':tagId']), + 'reveal_tag' => $this->router->generate('netgen_tags_admin_tag_reveal', ['tagId' => ':tagId']), ]; } @@ -180,6 +184,16 @@ private function getTagTreeData(Tag $tag, bool $isRoot = false): array 'url' => str_replace(':tagId', (string) $tag->id, $this->treeLinks['convert_tag']), 'text' => $this->treeLabels['convert_tag'], ], + [ + 'name' => 'hide_tag', + 'url' => str_replace(':tagId', (string) $tag->id, $this->treeLinks['hide_tag']), + 'text' => $this->treeLabels['hide_tag'], + ], + [ + 'name' => 'reveal_tag', + 'url' => str_replace(':tagId', (string) $tag->id, $this->treeLinks['reveal_tag']), + 'text' => $this->treeLabels['reveal_tag'], + ], ], ], ]; diff --git a/bundle/Resources/translations/netgen_tags_admin.en.yml b/bundle/Resources/translations/netgen_tags_admin.en.yml index 9eada6b0..ba430127 100644 --- a/bundle/Resources/translations/netgen_tags_admin.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin.en.yml @@ -106,6 +106,8 @@ tag.tree.delete_tag: 'Delete tag' tag.tree.merge_tag: 'Merge tag' tag.tree.convert_tag: 'Convert to synonym' tag.tree.add_synonym: 'Add synonym' +tag.tree.hide_tag: 'Hide tag' +tag.tree.reveal_tag: 'Reveal tag' tag.tree.no_tag_selected: 'no tag' tag.tree.select_tag: 'Select tag' diff --git a/bundle/Resources/translations/netgen_tags_admin.fr.yml b/bundle/Resources/translations/netgen_tags_admin.fr.yml index b68542bd..1cdd615c 100644 --- a/bundle/Resources/translations/netgen_tags_admin.fr.yml +++ b/bundle/Resources/translations/netgen_tags_admin.fr.yml @@ -63,7 +63,7 @@ tag.add_synonym.title: 'Ajouter un synonyme' tag.convert.title: 'Convertir en synonyme' tag.hide.title: 'Cacher le tag' -tag.reveal.title: 'Désactiver le tag' +tag.reveal.title: 'Révéler le tag' tag.move_tags.title: 'Déplacer les tags' tag.move_tags.message: 'Êtes-vous sûr de vouloir déplacer les tags sélectionnés ?' @@ -95,6 +95,8 @@ tag.tree.delete_tag: 'Supprimer le tag' tag.tree.merge_tag: 'Fusionner le tag' tag.tree.convert_tag: 'Convertir en synonyme' tag.tree.add_synonym: 'Ajouter un synonyme' +tag.tree.hide_tag: 'Cacher le tag' +tag.tree.reveal_tag: 'Révéler le tag' tag.tree.no_tag_selected: 'pas de tag' tag.tree.select_tag: 'Sélectionner un tag' From 37da894c6452305f2eb4b7c946bcac62ffbe5aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Wed, 11 Jun 2025 10:43:15 +0200 Subject: [PATCH 35/59] NGSTACK-977 add visibility information for children when listing them for some tag --- bundle/Resources/views/admin/tag/children.html.twig | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bundle/Resources/views/admin/tag/children.html.twig b/bundle/Resources/views/admin/tag/children.html.twig index 4d454f91..8e060ffc 100644 --- a/bundle/Resources/views/admin/tag/children.html.twig +++ b/bundle/Resources/views/admin/tag/children.html.twig @@ -41,7 +41,16 @@ {% endif %} {{ child.id }} - {{ child.keyword }} + + + {{ child.keyword }} + {% if child.isHidden %} + ({{ 'tag.hidden'|trans|lower }}) + {% elseif child.isInvisible %} + ({{ 'tag.hidden_by_parent'|trans }}) + {% endif %} + + {% for languageCode in child.keywords|keys %} {% if can_edit %}{% endif %} From e69b243b854d2746adcb824de1d836c0e0d6f142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Wed, 11 Jun 2025 10:44:28 +0200 Subject: [PATCH 36/59] NGSTACK-977 not show hidden tags when trying to search for them in eztags field --- bundle/Controller/Admin/FieldController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/bundle/Controller/Admin/FieldController.php b/bundle/Controller/Admin/FieldController.php index 50c7ac24..0a072f50 100644 --- a/bundle/Controller/Admin/FieldController.php +++ b/bundle/Controller/Admin/FieldController.php @@ -37,6 +37,7 @@ public function autoCompleteAction(Request $request): JsonResponse $searchResult = $this->tagsService->searchTags( $request->query->get('searchString') ?? '', $request->query->get('locale') ?? '', + showHidden: false, ); $data = $data = $this->filterTags($searchResult->tags, $subTreeLimit, $hideRootTag); From 514e3d0fb289f5fbdfed4615aea6f3574f110676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Wed, 11 Jun 2025 10:45:31 +0200 Subject: [PATCH 37/59] NGSTACK-977 update postgresql schema and legacy.yaml file with 'is_hidden' and 'is_invisible' properties --- bundle/Resources/schema/legacy.yaml | 10 ++++++++++ bundle/Resources/sql/postgresql/schema.sql | 2 ++ 2 files changed, 12 insertions(+) diff --git a/bundle/Resources/schema/legacy.yaml b/bundle/Resources/schema/legacy.yaml index dbdfd035..4bcc885f 100644 --- a/bundle/Resources/schema/legacy.yaml +++ b/bundle/Resources/schema/legacy.yaml @@ -55,6 +55,16 @@ tables: nullable: false options: default: '0' + is_hidden: + type: tinyint + nullable: false + options: + default: '0' + is_invisible: + type: tinyint + nullable: false + options: + default: '0' indexes: idx_eztags_keyword: fields: [keyword] diff --git a/bundle/Resources/sql/postgresql/schema.sql b/bundle/Resources/sql/postgresql/schema.sql index b86c4705..36aa10d7 100644 --- a/bundle/Resources/sql/postgresql/schema.sql +++ b/bundle/Resources/sql/postgresql/schema.sql @@ -10,6 +10,8 @@ CREATE TABLE eztags ( remote_id varchar(100) NOT NULL default '', main_language_id integer not null default 0, language_mask integer not null default 0, + is_hidden integer not null default 0, + is_invisible integer not null default 0, PRIMARY KEY (id), CONSTRAINT idx_eztags_remote_id UNIQUE (remote_id) ); From 81d40076cf9a82826ebab7676d640243fbfa4396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 12 Jun 2025 13:10:58 +0200 Subject: [PATCH 38/59] NGSTACK-977 update PHPDoc for isHidden and isInvisible Tag properties --- bundle/API/Repository/Values/Tags/Tag.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bundle/API/Repository/Values/Tags/Tag.php b/bundle/API/Repository/Values/Tags/Tag.php index d60d2d67..f2aade6e 100644 --- a/bundle/API/Repository/Values/Tags/Tag.php +++ b/bundle/API/Repository/Values/Tags/Tag.php @@ -107,12 +107,13 @@ final class Tag extends ValueObject protected ?string $prioritizedLanguageCode; /** - * Indicates if the Tag object is visible or not. + * Indicates that the Tag is hidden. */ protected bool $isHidden; /** - * Indicates if the Tag object is located under another hidden Tag object. + * Indicates that the Tag object is not visible, being either hidden itself, + * or implicitly hidden by parent or ancestor Tag object. */ protected bool $isInvisible; From a720391afb7e8ebaff55da0defe577abe07c88d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 12 Jun 2025 13:11:43 +0200 Subject: [PATCH 39/59] NGSTACK-977 modify 'tags_reveal' to 'tags_revealed' translation message --- bundle/Controller/Admin/TagController.php | 2 +- bundle/Resources/translations/netgen_tags_admin_flash.en.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bundle/Controller/Admin/TagController.php b/bundle/Controller/Admin/TagController.php index fa54400c..e7106ad1 100644 --- a/bundle/Controller/Admin/TagController.php +++ b/bundle/Controller/Admin/TagController.php @@ -755,7 +755,7 @@ public function revealTagsAction(Request $request, ?Tag $parentTag = null): Resp $this->tagsService->revealTag($tagObject); } - $this->addFlashMessage('success', 'tags_reveal'); + $this->addFlashMessage('success', 'tags_revealed'); return $this->redirectToTag($parentTag); } diff --git a/bundle/Resources/translations/netgen_tags_admin_flash.en.yml b/bundle/Resources/translations/netgen_tags_admin_flash.en.yml index 4461e7ab..1f4d5dad 100644 --- a/bundle/Resources/translations/netgen_tags_admin_flash.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin_flash.en.yml @@ -13,7 +13,7 @@ success.tags_moved: 'Tags have been moved successfully' success.tags_copied: 'Tags have been copied successfully' success.tags_deleted: 'Tags have been deleted successfully' success.tags_hidden: 'Tags have been hidden successfully' -success.tags_reveal: 'Tags have been revealed successfully' +success.tags_revealed: 'Tags have been revealed successfully' success.translation_removed: 'Translation for locale "%locale%" has been successfully removed' success.main_translation_set: 'Translation for locale "%locale%" has been set as new main translation' success.always_available_set: 'Always available flag has been successfully updated' From a69c38cf12cab6db5c58c5070ff7c6e88e74ef11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 12 Jun 2025 13:21:29 +0200 Subject: [PATCH 40/59] NGSTACK-977 extract TagTreeText formatting into a separate function and remove double cast from the Mapper --- bundle/Controller/Admin/TreeController.php | 34 +++++++++---------- .../Core/Persistence/Legacy/Tags/Mapper.php | 4 +-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/bundle/Controller/Admin/TreeController.php b/bundle/Controller/Admin/TreeController.php index 75eda913..1b0b7346 100644 --- a/bundle/Controller/Admin/TreeController.php +++ b/bundle/Controller/Admin/TreeController.php @@ -124,24 +124,10 @@ private function getRootTreeData(): array */ private function getTagTreeData(Tag $tag, bool $isRoot = false): array { - $synonymCount = $this->tagsService->getTagSynonymCount($tag); - - $text = $this->escape($tag->keyword); - - if ($tag->isHidden) { - $text .= ' (' . mb_strtolower($this->translator->trans('tag.hidden', [], 'netgen_tags_admin')) . ')'; - } elseif ($tag->isInvisible) { - $text .= ' (' . $this->translator->trans('tag.hidden_by_parent', [], 'netgen_tags_admin') . ')'; - } - - if ($synonymCount > 0) { - $text .= ' (+' . $synonymCount . ')'; - } - return [ 'id' => $tag->id, 'parent' => $isRoot ? '#' : $tag->parentTagId, - 'text' => $text, + 'text' => $this->formatTagTreeText($tag), 'children' => $this->tagsService->getTagChildrenCount($tag) > 0, 'hidden' => $tag->isHidden, 'invisible' => $tag->isInvisible, @@ -199,8 +185,22 @@ private function getTagTreeData(Tag $tag, bool $isRoot = false): array ]; } - private function escape(string $string): string + private function formatTagTreeText(Tag $tag): string { - return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8'); + $synonymCount = $this->tagsService->getTagSynonymCount($tag); + + $text = htmlspecialchars($tag->keyword, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8'); + + if ($tag->isHidden) { + $text .= ' (' . mb_strtolower($this->translator->trans('tag.hidden', [], 'netgen_tags_admin')) . ')'; + } elseif ($tag->isInvisible) { + $text .= ' (' . $this->translator->trans('tag.hidden_by_parent', [], 'netgen_tags_admin') . ')'; + } + + if ($synonymCount > 0) { + $text .= ' (+' . $synonymCount . ')'; + } + + return $text; } } diff --git a/bundle/Core/Persistence/Legacy/Tags/Mapper.php b/bundle/Core/Persistence/Legacy/Tags/Mapper.php index e7e48e4b..d8c4f796 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Mapper.php +++ b/bundle/Core/Persistence/Legacy/Tags/Mapper.php @@ -62,8 +62,8 @@ public function extractTagListFromRows(array $rows): array $tag->alwaysAvailable = (bool) ((int) $row['language_mask'] & 1); $tag->mainLanguageCode = $this->languageHandler->load($row['main_language_id'])->languageCode; $tag->languageIds = $this->languageMaskGenerator->extractLanguageIdsFromMask((int) $row['language_mask']); - $tag->isHidden = (bool) ((int) $row['is_hidden']); - $tag->isInvisible = (bool) ((int) $row['is_invisible']); + $tag->isHidden = (bool) $row['is_hidden']; + $tag->isInvisible = (bool) $row['is_invisible']; $tagList[$tagId] = $tag; } From 08ef43df4dd3ce63849626471e3af1f7834c845e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Tue, 17 Jun 2025 15:50:28 +0200 Subject: [PATCH 41/59] NGSTACK-977 add upgrade instructions for tag visibility to UPGRADE.md file --- doc/UPGRADE.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/doc/UPGRADE.md b/doc/UPGRADE.md index 67e8aa91..8a6ca6e6 100644 --- a/doc/UPGRADE.md +++ b/doc/UPGRADE.md @@ -1,6 +1,28 @@ Netgen Tags Bundle upgrade instructions ======================================= +Upgrade from 5.0 to 5.4 +----------------------- + +Tags Bundle 5.4 introduces support for tag visibility - now you can hide and reveal tags, just the same as content in +Ibexa Platform. Tags that are explicitly hidden or invisible because one of their ancestor is hidden cannot be added to +content. + +Please make sure to update Netgen Tags table to include `is_hidden` and `is_invisible` columns. + +If you're using MySQL, run the commands below: + +```sql +ALTER TABLE `eztags` ADD COLUMN `is_hidden` TINYINT NOT NULL DEFAULT 0; +ALTER TABLE `eztags` ADD COLUMN `is_invisible` TINYINT NOT NULL DEFAULT 0; +``` + +If you're using PostgreSQL, run the commands below: +```sql +ALTER TABLE `eztags` ADD COLUMN `is_hidden` INTEGER NOT NULL DEFAULT 0; +ALTER TABLE `eztags` ADD COLUMN `is_invisible` INTEGER NOT NULL DEFAULT 0; +``` + Upgrade from 4.0 to 5.0 ----------------------- From 550f0e3b3f294a7ca8633ca3d9905264247eb4ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Mon, 23 Jun 2025 09:40:26 +0200 Subject: [PATCH 42/59] NGSTACK-977 update hideAction() and revealAction() methods for hiding and revealing a tag with CSRF token check --- bundle/Controller/Admin/TagController.php | 42 ++++++++++++++++--- .../translations/netgen_tags_admin.en.yml | 3 ++ .../netgen_tags_admin_flash.en.yml | 2 +- .../Resources/views/admin/tag/hide.html.twig | 17 ++++++++ .../views/admin/tag/reveal.html.twig | 17 ++++++++ 5 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 bundle/Resources/views/admin/tag/hide.html.twig create mode 100644 bundle/Resources/views/admin/tag/reveal.html.twig diff --git a/bundle/Controller/Admin/TagController.php b/bundle/Controller/Admin/TagController.php index e7106ad1..221125e9 100644 --- a/bundle/Controller/Admin/TagController.php +++ b/bundle/Controller/Admin/TagController.php @@ -525,22 +525,52 @@ public function hideAction(Request $request, Tag $tag): Response { $this->denyAccessUnlessGranted('ibexa:tags:hide' . ($tag->isSynonym() ? 'synonym' : '')); - $this->tagsService->hideTag($tag); + if ($request->request->has('HideTagButton')) { + if (!$this->isCsrfTokenValid('netgen_tags_admin', (string) ($request->request->get('_csrf_token') ?? ''))) { + $this->addFlashMessage('errors', 'invalid_csrf_token'); + + return $this->redirectToTag($tag); + } - $this->addFlashMessage('success', 'tag_hidden', ['%tagKeyword%' => $tag->keyword]); + $this->tagsService->hideTag($tag); - return $this->redirectToTag($tag); + $this->addFlashMessage('success', 'tag_hidden', ['%tagKeyword%' => $tag->keyword]); + + return $this->redirectToTag($tag); + } + + return $this->render( + '@NetgenTags/admin/tag/hide.html.twig', + [ + 'tag' => $tag, + ], + ); } public function revealAction(Request $request, Tag $tag): Response { $this->denyAccessUnlessGranted('ibexa:tags:reveal' . ($tag->isSynonym() ? 'synonym' : '')); - $this->tagsService->revealTag($tag); + if ($request->request->has('RevealTagButton')) { + if (!$this->isCsrfTokenValid('netgen_tags_admin', (string) ($request->request->get('_csrf_token') ?? ''))) { + $this->addFlashMessage('errors', 'invalid_csrf_token'); + + return $this->redirectToTag($tag); + } - $this->addFlashMessage('success', 'tag_reveal', ['%tagKeyword%' => $tag->keyword]); + $this->tagsService->revealTag($tag); - return $this->redirectToTag($tag); + $this->addFlashMessage('success', 'tag_revealed', ['%tagKeyword%' => $tag->keyword]); + + return $this->redirectToTag($tag); + } + + return $this->render( + '@NetgenTags/admin/tag/reveal.html.twig', + [ + 'tag' => $tag, + ], + ); } /** diff --git a/bundle/Resources/translations/netgen_tags_admin.en.yml b/bundle/Resources/translations/netgen_tags_admin.en.yml index ba430127..a94832cb 100644 --- a/bundle/Resources/translations/netgen_tags_admin.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin.en.yml @@ -74,7 +74,10 @@ tag.add_synonym.title: 'Add synonym' tag.convert.title: 'Convert to synonym' tag.hide.title: 'Hide tag' +tag.hide.message: 'Are you sure you want to hide the "%tagKeyword%" tag? All descendant tags that are not explicitly hidden will then become invisible and marked as "hidden by parent".' + tag.reveal.title: 'Reveal tag' +tag.reveal.message: 'Are you sure you want to reveal the "%tagKeyword%" tag? All of its descendant tags will become visible again, except those that are explicitly hidden themselves or have another hidden ancestor.' tag.move_tags.title: 'Move tags' tag.move_tags.message: 'Are you sure you want to move the selected tags?' diff --git a/bundle/Resources/translations/netgen_tags_admin_flash.en.yml b/bundle/Resources/translations/netgen_tags_admin_flash.en.yml index 1f4d5dad..8c59e976 100644 --- a/bundle/Resources/translations/netgen_tags_admin_flash.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin_flash.en.yml @@ -18,4 +18,4 @@ success.translation_removed: 'Translation for locale "%locale%" has been success success.main_translation_set: 'Translation for locale "%locale%" has been set as new main translation' success.always_available_set: 'Always available flag has been successfully updated' success.tag_hidden: 'Tag "%tagKeyword%" has been hidden' -success.tag_reveal: 'Tag "%tagKeyword%" has been revealed' +success.tag_revealed: 'Tag "%tagKeyword%" has been revealed' diff --git a/bundle/Resources/views/admin/tag/hide.html.twig b/bundle/Resources/views/admin/tag/hide.html.twig new file mode 100644 index 00000000..21b3aa58 --- /dev/null +++ b/bundle/Resources/views/admin/tag/hide.html.twig @@ -0,0 +1,17 @@ +{% extends netgen_tags_admin.pageLayoutTemplate %} + +{% trans_default_domain 'netgen_tags_admin' %} + +{% block content %} +

{{ 'tag.hide.title'|trans }}: {{ tag.keyword }} [{{ tag.id }}]

+ +

{{ 'tag.hide.message'|trans({'%tagKeyword%': tag.keyword}) }}

+ + {% dump(tag) %} + +
+ + + {{ 'tag.button.no'|trans }} +
+{% endblock %} diff --git a/bundle/Resources/views/admin/tag/reveal.html.twig b/bundle/Resources/views/admin/tag/reveal.html.twig new file mode 100644 index 00000000..a8d77b64 --- /dev/null +++ b/bundle/Resources/views/admin/tag/reveal.html.twig @@ -0,0 +1,17 @@ +{% extends netgen_tags_admin.pageLayoutTemplate %} + +{% trans_default_domain 'netgen_tags_admin' %} + +{% block content %} +

{{ 'tag.reveal.title'|trans }}: {{ tag.keyword }} [{{ tag.id }}]

+ +

{{ 'tag.reveal.message'|trans({'%tagKeyword%': tag.keyword}) }}

+ + {% dump(tag) %} + +
+ + + {{ 'tag.button.no'|trans }} +
+{% endblock %} From 4a174cc82497a6c74cee527b8a6100cbfb53ed94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Mon, 23 Jun 2025 15:45:01 +0200 Subject: [PATCH 43/59] NGSTACK-977 separate escape logic from the formatting logic for tag keyword in TreeController --- bundle/Controller/Admin/TreeController.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/bundle/Controller/Admin/TreeController.php b/bundle/Controller/Admin/TreeController.php index 1b0b7346..51b56c91 100644 --- a/bundle/Controller/Admin/TreeController.php +++ b/bundle/Controller/Admin/TreeController.php @@ -185,22 +185,27 @@ private function getTagTreeData(Tag $tag, bool $isRoot = false): array ]; } + private function escape(string $string): string + { + return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8'); + } + private function formatTagTreeText(Tag $tag): string { $synonymCount = $this->tagsService->getTagSynonymCount($tag); - $text = htmlspecialchars($tag->keyword, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8'); + $result = $tag->keyword; if ($tag->isHidden) { - $text .= ' (' . mb_strtolower($this->translator->trans('tag.hidden', [], 'netgen_tags_admin')) . ')'; + $result .= ' (' . mb_strtolower($this->translator->trans('tag.hidden', [], 'netgen_tags_admin')) . ')'; } elseif ($tag->isInvisible) { - $text .= ' (' . $this->translator->trans('tag.hidden_by_parent', [], 'netgen_tags_admin') . ')'; + $result .= ' (' . $this->translator->trans('tag.hidden_by_parent', [], 'netgen_tags_admin') . ')'; } if ($synonymCount > 0) { - $text .= ' (+' . $synonymCount . ')'; + $result .= ' (+' . $synonymCount . ')'; } - return $text; + return $this->escape($result); } } From 6692248b769f5df03decc1f4f343c1f8cc419b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Mon, 23 Jun 2025 16:12:49 +0200 Subject: [PATCH 44/59] NGSTACK-977 rename 'showHidden' to 'showHiddenTags' parameter in configTree, Service, Handler and Gateway layers --- bundle/API/Repository/TagsService.php | 14 ++++----- bundle/Core/Event/TagsService.php | 28 ++++++++--------- bundle/Core/Persistence/Cache/TagsHandler.php | 28 ++++++++--------- .../Core/Persistence/Legacy/Tags/Gateway.php | 12 ++++---- .../Legacy/Tags/Gateway/DoctrineDatabase.php | 30 +++++++++---------- .../Tags/Gateway/ExceptionConversion.php | 24 +++++++-------- .../Core/Persistence/Legacy/Tags/Handler.php | 30 +++++++++---------- bundle/Core/Repository/TagsService.php | 28 ++++++++--------- bundle/Core/SiteAccessAware/TagsService.php | 28 ++++++++--------- bundle/DependencyInjection/Configuration.php | 2 +- .../NetgenTagsExtension.php | 2 +- bundle/SPI/Persistence/Tags/Handler.php | 14 ++++----- 12 files changed, 120 insertions(+), 120 deletions(-) diff --git a/bundle/API/Repository/TagsService.php b/bundle/API/Repository/TagsService.php index 2676abd3..d9b76dff 100644 --- a/bundle/API/Repository/TagsService.php +++ b/bundle/API/Repository/TagsService.php @@ -76,7 +76,7 @@ public function loadTagByUrl(string $url, array $languages): Tag; * * @return \Netgen\TagsBundle\API\Repository\Values\Tags\TagList */ - public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList; + public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): TagList; /** * Returns the number of children of a tag object. @@ -89,7 +89,7 @@ public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = * * @return int */ - public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; + public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int; /** * Loads tags by specified keyword. @@ -104,7 +104,7 @@ public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, * * @return \Netgen\TagsBundle\API\Repository\Values\Tags\TagList */ - public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): TagList; + public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): TagList; /** * Returns the number of tags by specified keyword. @@ -117,7 +117,7 @@ public function loadTagsByKeyword(string $keyword, string $language, bool $useAl * * @return int */ - public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; + public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int; /** * Search for tags. @@ -132,7 +132,7 @@ public function getTagsByKeywordCount(string $keyword, string $language, bool $u * * @return \Netgen\TagsBundle\API\Repository\Values\Tags\SearchResult */ - public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult; + public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): SearchResult; /** * Loads synonyms of a tag object. @@ -148,7 +148,7 @@ public function searchTags(string $searchString, string $language, bool $useAlwa * * @return \Netgen\TagsBundle\API\Repository\Values\Tags\TagList */ - public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList; + public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): TagList; /** * Returns the number of synonyms of a tag object. @@ -162,7 +162,7 @@ public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?arr * * @return int */ - public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; + public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int; /** * Loads content related to $tag. diff --git a/bundle/Core/Event/TagsService.php b/bundle/Core/Event/TagsService.php index 66709881..21a380d9 100644 --- a/bundle/Core/Event/TagsService.php +++ b/bundle/Core/Event/TagsService.php @@ -38,39 +38,39 @@ public function loadTagByUrl(string $url, array $languages): Tag return $this->service->loadTagByUrl($url, $languages); } - public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList + public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): TagList { - return $this->service->loadTagChildren($tag, $offset, $limit, $languages, $useAlwaysAvailable, $showHidden); + return $this->service->loadTagChildren($tag, $offset, $limit, $languages, $useAlwaysAvailable, $showHiddenTags); } - public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { - return $this->service->getTagChildrenCount($tag, $languages, $useAlwaysAvailable, $showHidden); + return $this->service->getTagChildrenCount($tag, $languages, $useAlwaysAvailable, $showHiddenTags); } - public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): TagList + public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): TagList { - return $this->service->loadTagsByKeyword($keyword, $language, $useAlwaysAvailable, $offset, $limit, $showHidden); + return $this->service->loadTagsByKeyword($keyword, $language, $useAlwaysAvailable, $offset, $limit, $showHiddenTags); } - public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { - return $this->service->getTagsByKeywordCount($keyword, $language, $useAlwaysAvailable, $showHidden); + return $this->service->getTagsByKeywordCount($keyword, $language, $useAlwaysAvailable, $showHiddenTags); } - public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult + public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): SearchResult { - return $this->service->searchTags($searchString, $language, $useAlwaysAvailable, $offset, $limit, $showHidden); + return $this->service->searchTags($searchString, $language, $useAlwaysAvailable, $offset, $limit, $showHiddenTags); } - public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList + public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): TagList { - return $this->service->loadTagSynonyms($tag, $offset, $limit, $languages, $useAlwaysAvailable, $showHidden); + return $this->service->loadTagSynonyms($tag, $offset, $limit, $languages, $useAlwaysAvailable, $showHiddenTags); } - public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { - return $this->service->getTagSynonymCount($tag, $languages, $useAlwaysAvailable, $showHidden); + return $this->service->getTagSynonymCount($tag, $languages, $useAlwaysAvailable, $showHiddenTags); } public function getRelatedContent(Tag $tag, int $offset = 0, int $limit = -1, bool $returnContentInfo = true, array $additionalCriteria = [], array $sortClauses = []): array diff --git a/bundle/Core/Persistence/Cache/TagsHandler.php b/bundle/Core/Persistence/Cache/TagsHandler.php index 5d065c6d..ef2dd1e9 100644 --- a/bundle/Core/Persistence/Cache/TagsHandler.php +++ b/bundle/Core/Persistence/Cache/TagsHandler.php @@ -155,42 +155,42 @@ public function loadTagByKeywordAndParentId(string $keyword, int $parentTagId, ? return $this->tagsHandler->loadTagByKeywordAndParentId($keyword, $parentTagId, $translations, $useAlwaysAvailable); } - public function loadChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array + public function loadChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): array { $this->logger->logCall(__METHOD__, ['tag' => $tagId, 'translations' => $translations, 'useAlwaysAvailable' => $useAlwaysAvailable]); - return $this->tagsHandler->loadChildren($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHidden); + return $this->tagsHandler->loadChildren($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHiddenTags); } - public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { $this->logger->logCall(__METHOD__, ['tag' => $tagId, 'translations' => $translations, 'useAlwaysAvailable' => $useAlwaysAvailable]); - return $this->tagsHandler->getChildrenCount($tagId, $translations, $useAlwaysAvailable, $showHidden); + return $this->tagsHandler->getChildrenCount($tagId, $translations, $useAlwaysAvailable, $showHiddenTags); } - public function loadTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): array + public function loadTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): array { $this->logger->logCall(__METHOD__, ['keyword' => $keyword, 'translation' => $translation, 'useAlwaysAvailable' => $useAlwaysAvailable]); - return $this->tagsHandler->loadTagsByKeyword($keyword, $translation, $useAlwaysAvailable, $offset, $limit, $showHidden); + return $this->tagsHandler->loadTagsByKeyword($keyword, $translation, $useAlwaysAvailable, $offset, $limit, $showHiddenTags); } - public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { $this->logger->logCall(__METHOD__, ['keyword' => $keyword, 'translation' => $translation, 'useAlwaysAvailable' => $useAlwaysAvailable]); - return $this->tagsHandler->getTagsByKeywordCount($keyword, $translation, $useAlwaysAvailable, $showHidden); + return $this->tagsHandler->getTagsByKeywordCount($keyword, $translation, $useAlwaysAvailable, $showHiddenTags); } - public function searchTags(string $searchString, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult + public function searchTags(string $searchString, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): SearchResult { $this->logger->logCall(__METHOD__, ['searchString' => $searchString, 'translation' => $translation, 'useAlwaysAvailable' => $useAlwaysAvailable]); - return $this->tagsHandler->searchTags($searchString, $translation, $useAlwaysAvailable, $offset, $limit, $showHidden); + return $this->tagsHandler->searchTags($searchString, $translation, $useAlwaysAvailable, $offset, $limit, $showHiddenTags); } - public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array + public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): array { // Method caches all synonyms in cache and only uses offset / limit to slice the cached result $translationsKey = count($translations ?? []) === 0 @@ -208,7 +208,7 @@ public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?arra $this->logger->logCall(__METHOD__, ['tag' => $tagId, 'translations' => $translations, 'useAlwaysAvailable' => $useAlwaysAvailable]); $tagInfo = $this->loadTagInfo($tagId); - $synonyms = $this->tagsHandler->loadSynonyms($tagId, 0, -1, $translations, $useAlwaysAvailable, $showHidden); + $synonyms = $this->tagsHandler->loadSynonyms($tagId, 0, -1, $translations, $useAlwaysAvailable, $showHiddenTags); $cacheItem->set($synonyms); $cacheTags = [$this->getCacheTags($tagInfo->id, $tagInfo->pathString)]; @@ -221,11 +221,11 @@ public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?arra return array_slice($synonyms, $offset, $limit > -1 ? $limit : null); } - public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { $this->logger->logCall(__METHOD__, ['tag' => $tagId, 'translations' => $translations, 'useAlwaysAvailable' => $useAlwaysAvailable]); - return $this->tagsHandler->getSynonymCount($tagId, $translations, $useAlwaysAvailable, $showHidden); + return $this->tagsHandler->getSynonymCount($tagId, $translations, $useAlwaysAvailable, $showHiddenTags); } public function create(CreateStruct $createStruct): Tag diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway.php b/bundle/Core/Persistence/Legacy/Tags/Gateway.php index 02865c6e..184c88e7 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway.php @@ -40,36 +40,36 @@ abstract public function getFullTagDataByKeywordAndParentId(string $keyword, int * * If $limit = -1 all children starting at $offset are returned. */ - abstract public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array; + abstract public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): array; /** * Returns how many tags exist below tag identified by $tagId. */ - abstract public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; + abstract public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int; /** * Returns data for tags identified by given $keyword. * * If $limit = -1 all tags starting at $offset are returned. */ - abstract public function getTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): array; + abstract public function getTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): array; /** * Returns how many tags exist with $keyword. */ - abstract public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHidden = null, bool $exactMatch = true): int; + abstract public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null, bool $exactMatch = true): int; /** * Returns data for synonyms of the tag identified by given $tagId. * * If $limit = -1 all synonyms starting at $offset are returned. */ - abstract public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array; + abstract public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): array; /** * Returns how many synonyms exist for a tag identified by $tagId. */ - abstract public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; + abstract public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int; /** * Moves the synonym identified by $synonymId to tag identified by $mainTagData. diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index 9c3cde5e..c564d2c2 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -126,11 +126,11 @@ public function getFullTagDataByKeywordAndParentId(string $keyword, int $parentI return $query->execute()->fetchAll(FetchMode::ASSOCIATIVE); } - public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array + public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): array { $tagIdsQuery = $this->createTagIdsQuery($translations, $useAlwaysAvailable); - if ($showHidden !== null && $showHidden === false) { + if ($showHiddenTags !== null && $showHiddenTags === false) { $tagIdsQuery->andWhere( $tagIdsQuery->expr()->neq('is_hidden', '1'), ); @@ -162,7 +162,7 @@ public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $query = $this->createTagFindQuery($translations, $useAlwaysAvailable); - if ($showHidden !== null && $showHidden === false) { + if ($showHiddenTags !== null && $showHiddenTags === false) { $query->andWhere( $query->expr()->neq('is_hidden', '1'), ); @@ -180,11 +180,11 @@ public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array return $query->execute()->fetchAll(FetchMode::ASSOCIATIVE); } - public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { $query = $this->createTagCountQuery($translations, $useAlwaysAvailable); - if ($showHidden !== null && $showHidden === false) { + if ($showHiddenTags !== null && $showHiddenTags === false) { $query->andWhere( $query->expr()->neq('is_hidden', '1'), ); @@ -205,12 +205,12 @@ public function getChildrenCount(int $tagId, ?array $translations = null, bool $ return (int) $rows[0]['count']; } - public function getTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): array + public function getTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): array { $databasePlatform = $this->connection->getDatabasePlatform(); $tagIdsQuery = $this->createTagIdsQuery([$translation], $useAlwaysAvailable); - if ($showHidden !== null && $showHidden === false) { + if ($showHiddenTags !== null && $showHiddenTags === false) { $tagIdsQuery->andWhere( $tagIdsQuery->expr()->neq('is_hidden', '1'), ); @@ -249,7 +249,7 @@ public function getTagsByKeyword(string $keyword, string $translation, bool $use $query = $this->createTagFindQuery([$translation], $useAlwaysAvailable); - if ($showHidden !== null && $showHidden === false) { + if ($showHiddenTags !== null && $showHiddenTags === false) { $query->andWhere( $query->expr()->neq('is_hidden', '1'), ); @@ -267,12 +267,12 @@ public function getTagsByKeyword(string $keyword, string $translation, bool $use return $query->execute()->fetchAll(FetchMode::ASSOCIATIVE); } - public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHidden = null, bool $exactMatch = true): int + public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null, bool $exactMatch = true): int { $databasePlatform = $this->connection->getDatabasePlatform(); $query = $this->createTagCountQuery([$translation, $useAlwaysAvailable]); - if ($showHidden !== null && $showHidden === false) { + if ($showHiddenTags !== null && $showHiddenTags === false) { $query->andWhere( $query->expr()->neq('is_hidden', '1'), ); @@ -299,11 +299,11 @@ public function getTagsByKeywordCount(string $keyword, string $translation, bool return (int) $rows[0]['count']; } - public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array + public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): array { $tagIdsQuery = $this->createTagIdsQuery($translations, $useAlwaysAvailable); - if ($showHidden !== null && $showHidden === false) { + if ($showHiddenTags !== null && $showHiddenTags === false) { $tagIdsQuery->andWhere( $tagIdsQuery->expr()->neq('is_hidden', '1'), ); @@ -331,7 +331,7 @@ public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $query = $this->createTagFindQuery($translations, $useAlwaysAvailable); - if ($showHidden !== null && $showHidden === false) { + if ($showHiddenTags !== null && $showHiddenTags === false) { $query->andWhere( $query->expr()->neq('is_hidden', '1'), ); @@ -347,11 +347,11 @@ public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array return $query->execute()->fetchAll(FetchMode::ASSOCIATIVE); } - public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { $query = $this->createTagCountQuery($translations, $useAlwaysAvailable); - if ($showHidden !== null && $showHidden === false) { + if ($showHiddenTags !== null && $showHiddenTags === false) { $query->andWhere( $query->expr()->neq('is_hidden', '1'), ); diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php index a4c94c7f..1b67ff29 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/ExceptionConversion.php @@ -71,10 +71,10 @@ public function getFullTagDataByKeywordAndParentId(string $keyword, int $parentI } } - public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array + public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): array { try { - return $this->innerGateway->getChildren($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHidden); + return $this->innerGateway->getChildren($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHiddenTags); } catch (DBALException $e) { throw new RuntimeException('Database error', 0, $e); } catch (PDOException $e) { @@ -82,10 +82,10 @@ public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array } } - public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { try { - return $this->innerGateway->getChildrenCount($tagId, $translations, $useAlwaysAvailable, $showHidden); + return $this->innerGateway->getChildrenCount($tagId, $translations, $useAlwaysAvailable, $showHiddenTags); } catch (DBALException $e) { throw new RuntimeException('Database error', 0, $e); } catch (PDOException $e) { @@ -93,10 +93,10 @@ public function getChildrenCount(int $tagId, ?array $translations = null, bool $ } } - public function getTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): array + public function getTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, bool $exactMatch = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): array { try { - return $this->innerGateway->getTagsByKeyword($keyword, $translation, $useAlwaysAvailable, $exactMatch, $offset, $limit, $showHidden); + return $this->innerGateway->getTagsByKeyword($keyword, $translation, $useAlwaysAvailable, $exactMatch, $offset, $limit, $showHiddenTags); } catch (DBALException $e) { throw new RuntimeException('Database error', 0, $e); } catch (PDOException $e) { @@ -104,10 +104,10 @@ public function getTagsByKeyword(string $keyword, string $translation, bool $use } } - public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHidden = null, bool $exactMatch = true): int + public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null, bool $exactMatch = true): int { try { - return $this->innerGateway->getTagsByKeywordCount($keyword, $translation, $useAlwaysAvailable, $showHidden, $exactMatch); + return $this->innerGateway->getTagsByKeywordCount($keyword, $translation, $useAlwaysAvailable, $showHiddenTags, $exactMatch); } catch (DBALException $e) { throw new RuntimeException('Database error', 0, $e); } catch (PDOException $e) { @@ -115,10 +115,10 @@ public function getTagsByKeywordCount(string $keyword, string $translation, bool } } - public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array + public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): array { try { - return $this->innerGateway->getSynonyms($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHidden); + return $this->innerGateway->getSynonyms($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHiddenTags); } catch (DBALException $e) { throw new RuntimeException('Database error', 0, $e); } catch (PDOException $e) { @@ -126,10 +126,10 @@ public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array } } - public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { try { - return $this->innerGateway->getSynonymCount($tagId, $translations, $useAlwaysAvailable, $showHidden); + return $this->innerGateway->getSynonymCount($tagId, $translations, $useAlwaysAvailable, $showHiddenTags); } catch (DBALException $e) { throw new RuntimeException('Database error', 0, $e); } catch (PDOException $e) { diff --git a/bundle/Core/Persistence/Legacy/Tags/Handler.php b/bundle/Core/Persistence/Legacy/Tags/Handler.php index 5cc3cc5d..36d4002d 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Handler.php +++ b/bundle/Core/Persistence/Legacy/Tags/Handler.php @@ -89,34 +89,34 @@ public function loadTagByKeywordAndParentId(string $keyword, int $parentTagId, ? return reset($tag); } - public function loadChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array + public function loadChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): array { - $tags = $this->gateway->getChildren($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHidden); + $tags = $this->gateway->getChildren($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHiddenTags); return $this->mapper->extractTagListFromRows($tags); } - public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { - return $this->gateway->getChildrenCount($tagId, $translations, $useAlwaysAvailable, $showHidden); + return $this->gateway->getChildrenCount($tagId, $translations, $useAlwaysAvailable, $showHiddenTags); } - public function loadTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): array + public function loadTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): array { - $tags = $this->gateway->getTagsByKeyword($keyword, $translation, $useAlwaysAvailable, true, $offset, $limit, $showHidden); + $tags = $this->gateway->getTagsByKeyword($keyword, $translation, $useAlwaysAvailable, true, $offset, $limit, $showHiddenTags); return $this->mapper->extractTagListFromRows($tags); } - public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { - return $this->gateway->getTagsByKeywordCount($keyword, $translation, $useAlwaysAvailable, $showHidden); + return $this->gateway->getTagsByKeywordCount($keyword, $translation, $useAlwaysAvailable, $showHiddenTags); } - public function searchTags(string $searchString, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult + public function searchTags(string $searchString, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): SearchResult { - $tags = $this->gateway->getTagsByKeyword($searchString, $translation, $useAlwaysAvailable, false, $offset, $limit, $showHidden); - $totalCount = $this->gateway->getTagsByKeywordCount($searchString, $translation, $useAlwaysAvailable, $showHidden, false); + $tags = $this->gateway->getTagsByKeyword($searchString, $translation, $useAlwaysAvailable, false, $offset, $limit, $showHiddenTags); + $totalCount = $this->gateway->getTagsByKeywordCount($searchString, $translation, $useAlwaysAvailable, $showHiddenTags, false); return new SearchResult( [ @@ -126,16 +126,16 @@ public function searchTags(string $searchString, string $translation, bool $useA ); } - public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array + public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): array { - $tags = $this->gateway->getSynonyms($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHidden); + $tags = $this->gateway->getSynonyms($tagId, $offset, $limit, $translations, $useAlwaysAvailable, $showHiddenTags); return $this->mapper->extractTagListFromRows($tags); } - public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { - return $this->gateway->getSynonymCount($tagId, $translations, $useAlwaysAvailable, $showHidden); + return $this->gateway->getSynonymCount($tagId, $translations, $useAlwaysAvailable, $showHiddenTags); } public function create(CreateStruct $createStruct): Tag diff --git a/bundle/Core/Repository/TagsService.php b/bundle/Core/Repository/TagsService.php index eec3056a..6a2a36bc 100644 --- a/bundle/Core/Repository/TagsService.php +++ b/bundle/Core/Repository/TagsService.php @@ -152,7 +152,7 @@ public function loadTagByUrl(string $url, array $languages): Tag return $this->mapper->buildTagDomainObject($spiTag, $languages); } - public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList + public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): TagList { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); @@ -164,7 +164,7 @@ public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = $limit, $languages, $useAlwaysAvailable, - $showHidden, + $showHiddenTags, ); $tags = []; @@ -175,7 +175,7 @@ public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = return new TagList($tags); } - public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); @@ -185,17 +185,17 @@ public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, $tag?->id ?? 0, $languages, $useAlwaysAvailable, - $showHidden, + $showHiddenTags, ); } - public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): TagList + public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): TagList { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); } - $spiTags = $this->tagsHandler->loadTagsByKeyword($keyword, $language, $useAlwaysAvailable, $offset, $limit, $showHidden); + $spiTags = $this->tagsHandler->loadTagsByKeyword($keyword, $language, $useAlwaysAvailable, $offset, $limit, $showHiddenTags); $tags = []; foreach ($spiTags as $spiTag) { @@ -205,16 +205,16 @@ public function loadTagsByKeyword(string $keyword, string $language, bool $useAl return new TagList($tags); } - public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); } - return $this->tagsHandler->getTagsByKeywordCount($keyword, $language, $useAlwaysAvailable, $showHidden); + return $this->tagsHandler->getTagsByKeywordCount($keyword, $language, $useAlwaysAvailable, $showHiddenTags); } - public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult + public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): SearchResult { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); @@ -226,7 +226,7 @@ public function searchTags(string $searchString, string $language, bool $useAlwa $useAlwaysAvailable, $offset, $limit, - $showHidden, + $showHiddenTags, ); $tags = []; @@ -242,7 +242,7 @@ public function searchTags(string $searchString, string $language, bool $useAlwa ); } - public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList + public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): TagList { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); @@ -258,7 +258,7 @@ public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?arr $limit, $languages, $useAlwaysAvailable, - $showHidden, + $showHiddenTags, ); $tags = []; @@ -269,7 +269,7 @@ public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?arr return new TagList($tags); } - public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { if ($this->hasAccess('tags', 'read') === false) { throw new UnauthorizedException('tags', 'read'); @@ -283,7 +283,7 @@ public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $use $tag->id, $languages, $useAlwaysAvailable, - $showHidden, + $showHiddenTags, ); } diff --git a/bundle/Core/SiteAccessAware/TagsService.php b/bundle/Core/SiteAccessAware/TagsService.php index f03ec529..e7731905 100644 --- a/bundle/Core/SiteAccessAware/TagsService.php +++ b/bundle/Core/SiteAccessAware/TagsService.php @@ -57,7 +57,7 @@ public function loadTagByUrl(string $url, array $languages): Tag ); } - public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList + public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): TagList { return $this->innerService->loadTagChildren( $tag, @@ -65,21 +65,21 @@ public function loadTagChildren(?Tag $tag = null, int $offset = 0, int $limit = $limit, $this->languageResolver->getPrioritizedLanguages($languages), $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), - $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), + $showHiddenTags ?? $this->configResolver->getParameter('show_hidden_tags', 'netgen_tags'), ); } - public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getTagChildrenCount(?Tag $tag = null, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { return $this->innerService->getTagChildrenCount( $tag, $this->languageResolver->getPrioritizedLanguages($languages), $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), - $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), + $showHiddenTags ?? $this->configResolver->getParameter('show_hidden_tags', 'netgen_tags'), ); } - public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): TagList + public function loadTagsByKeyword(string $keyword, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): TagList { return $this->innerService->loadTagsByKeyword( $keyword, @@ -87,21 +87,21 @@ public function loadTagsByKeyword(string $keyword, string $language, bool $useAl $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), $offset, $limit, - $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), + $showHiddenTags ?? $this->configResolver->getParameter('show_hidden_tags', 'netgen_tags'), ); } - public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getTagsByKeywordCount(string $keyword, string $language, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { return $this->innerService->getTagsByKeywordCount( $keyword, $language, $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), - $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), + $showHiddenTags ?? $this->configResolver->getParameter('show_hidden_tags', 'netgen_tags'), ); } - public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult + public function searchTags(string $searchString, string $language, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): SearchResult { return $this->innerService->searchTags( $searchString, @@ -109,11 +109,11 @@ public function searchTags(string $searchString, string $language, bool $useAlwa $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), $offset, $limit, - $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), + $showHiddenTags ?? $this->configResolver->getParameter('show_hidden_tags', 'netgen_tags'), ); } - public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): TagList + public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): TagList { return $this->innerService->loadTagSynonyms( $tag, @@ -121,17 +121,17 @@ public function loadTagSynonyms(Tag $tag, int $offset = 0, int $limit = -1, ?arr $limit, $this->languageResolver->getPrioritizedLanguages($languages), $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), - $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), + $showHiddenTags ?? $this->configResolver->getParameter('show_hidden_tags', 'netgen_tags'), ); } - public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int + public function getTagSynonymCount(Tag $tag, ?array $languages = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int { return $this->innerService->getTagSynonymCount( $tag, $this->languageResolver->getPrioritizedLanguages($languages), $this->languageResolver->getUseAlwaysAvailable($useAlwaysAvailable), - $showHidden ?? $this->configResolver->getParameter('show_hidden', 'netgen_tags'), + $showHiddenTags ?? $this->configResolver->getParameter('show_hidden_tags', 'netgen_tags'), ); } diff --git a/bundle/DependencyInjection/Configuration.php b/bundle/DependencyInjection/Configuration.php index 9a234c40..cd0e9f05 100644 --- a/bundle/DependencyInjection/Configuration.php +++ b/bundle/DependencyInjection/Configuration.php @@ -156,7 +156,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->end() ->end() - ->booleanNode('show_hidden') + ->booleanNode('show_hidden_tags') ->info('Whether to show hidden tags or not') ->defaultTrue() ->end(); diff --git a/bundle/DependencyInjection/NetgenTagsExtension.php b/bundle/DependencyInjection/NetgenTagsExtension.php index 3cd07bd7..5fb3090c 100644 --- a/bundle/DependencyInjection/NetgenTagsExtension.php +++ b/bundle/DependencyInjection/NetgenTagsExtension.php @@ -122,7 +122,7 @@ static function (array $config, string $scope, ContextualizerInterface $c): void $c->setContextualParameter('admin.related_content_limit', $scope, $config['admin']['related_content_limit']); $c->setContextualParameter('field.autocomplete_limit', $scope, $config['field']['autocomplete_limit']); - $c->setContextualParameter('show_hidden', $scope, $config['show_hidden']); + $c->setContextualParameter('show_hidden_tags', $scope, $config['show_hidden_tags']); }, ); diff --git a/bundle/SPI/Persistence/Tags/Handler.php b/bundle/SPI/Persistence/Tags/Handler.php index 4fbee896..27ef2bb1 100644 --- a/bundle/SPI/Persistence/Tags/Handler.php +++ b/bundle/SPI/Persistence/Tags/Handler.php @@ -63,33 +63,33 @@ public function loadTagByKeywordAndParentId(string $keyword, int $parentTagId, ? * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ - public function loadChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array; + public function loadChildren(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): array; /** * Returns the number of children of a tag identified by $tagId. * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ - public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; + public function getChildrenCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int; /** * Loads tags with specified $keyword. * * If $limit = -1 all tags starting at $offset are returned. */ - public function loadTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): array; + public function loadTagsByKeyword(string $keyword, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): array; /** * Returns the number of tags with specified $keyword. */ - public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; + public function getTagsByKeywordCount(string $keyword, string $translation, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int; /** * Searches for tags. * * If $limit = -1 all tags starting at $offset are returned. */ - public function searchTags(string $searchString, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHidden = null): SearchResult; + public function searchTags(string $searchString, string $translation, bool $useAlwaysAvailable = true, int $offset = 0, int $limit = -1, ?bool $showHiddenTags = null): SearchResult; /** * Loads the synonyms of a tag identified by $tagId. @@ -98,14 +98,14 @@ public function searchTags(string $searchString, string $translation, bool $useA * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ - public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): array; + public function loadSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): array; /** * Returns the number of synonyms of a tag identified by $tagId. * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If the specified tag is not found */ - public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHidden = null): int; + public function getSynonymCount(int $tagId, ?array $translations = null, bool $useAlwaysAvailable = true, ?bool $showHiddenTags = null): int; /** * Creates the new tag. From 203dcd68ec7bc02cbb48580491eae3c3020f86ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Mon, 23 Jun 2025 16:23:59 +0200 Subject: [PATCH 45/59] NGSTACK-977 add MySQL and PostgreSQL upgrade scripts for 'is_hidden' and 'is_invisible' columns --- .../sql/upgrade/mysql/5.4/dbupdate-5.0-to-5.4.sql | 3 +++ .../upgrade/postgresql/5.4/dbupdate-5.0-to-5.4.sql | 3 +++ doc/UPGRADE.md | 13 ++----------- 3 files changed, 8 insertions(+), 11 deletions(-) create mode 100644 bundle/Resources/sql/upgrade/mysql/5.4/dbupdate-5.0-to-5.4.sql create mode 100644 bundle/Resources/sql/upgrade/postgresql/5.4/dbupdate-5.0-to-5.4.sql diff --git a/bundle/Resources/sql/upgrade/mysql/5.4/dbupdate-5.0-to-5.4.sql b/bundle/Resources/sql/upgrade/mysql/5.4/dbupdate-5.0-to-5.4.sql new file mode 100644 index 00000000..54433409 --- /dev/null +++ b/bundle/Resources/sql/upgrade/mysql/5.4/dbupdate-5.0-to-5.4.sql @@ -0,0 +1,3 @@ +ALTER TABLE `eztags` ADD COLUMN `is_hidden` TINYINT NOT NULL DEFAULT 0; + +ALTER TABLE `eztags` ADD COLUMN `is_invisible` TINYINT NOT NULL DEFAULT 0; diff --git a/bundle/Resources/sql/upgrade/postgresql/5.4/dbupdate-5.0-to-5.4.sql b/bundle/Resources/sql/upgrade/postgresql/5.4/dbupdate-5.0-to-5.4.sql new file mode 100644 index 00000000..61508a8f --- /dev/null +++ b/bundle/Resources/sql/upgrade/postgresql/5.4/dbupdate-5.0-to-5.4.sql @@ -0,0 +1,3 @@ +ALTER TABLE `eztags` ADD COLUMN `is_hidden` INTEGER NOT NULL DEFAULT 0; + +ALTER TABLE `eztags` ADD COLUMN `is_invisible` INTEGER NOT NULL DEFAULT 0; diff --git a/doc/UPGRADE.md b/doc/UPGRADE.md index 8a6ca6e6..51f2b825 100644 --- a/doc/UPGRADE.md +++ b/doc/UPGRADE.md @@ -10,18 +10,9 @@ content. Please make sure to update Netgen Tags table to include `is_hidden` and `is_invisible` columns. -If you're using MySQL, run the commands below: +MySQL upgrade script: `bundle/Resources/sql/upgrade/mysql/5.4/dbupdate-5.0-to-5.4.sql` -```sql -ALTER TABLE `eztags` ADD COLUMN `is_hidden` TINYINT NOT NULL DEFAULT 0; -ALTER TABLE `eztags` ADD COLUMN `is_invisible` TINYINT NOT NULL DEFAULT 0; -``` - -If you're using PostgreSQL, run the commands below: -```sql -ALTER TABLE `eztags` ADD COLUMN `is_hidden` INTEGER NOT NULL DEFAULT 0; -ALTER TABLE `eztags` ADD COLUMN `is_invisible` INTEGER NOT NULL DEFAULT 0; -``` +PostgreSQL upgrade script: `bundle/Resources/sql/upgrade/postgresql/5.4/dbupdate-5.0-to-5.4.sql` Upgrade from 4.0 to 5.0 ----------------------- From ec62925c14e8a6051376616c5f6ac81bb393ad50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Mon, 23 Jun 2025 16:27:57 +0200 Subject: [PATCH 46/59] NGSTACK-977 fix a call to searchTags() method in FieldController --- bundle/Controller/Admin/FieldController.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bundle/Controller/Admin/FieldController.php b/bundle/Controller/Admin/FieldController.php index 0a072f50..e7221b68 100644 --- a/bundle/Controller/Admin/FieldController.php +++ b/bundle/Controller/Admin/FieldController.php @@ -37,7 +37,10 @@ public function autoCompleteAction(Request $request): JsonResponse $searchResult = $this->tagsService->searchTags( $request->query->get('searchString') ?? '', $request->query->get('locale') ?? '', - showHidden: false, + true, + 0, + -1, + false, ); $data = $data = $this->filterTags($searchResult->tags, $subTreeLimit, $hideRootTag); From c05ab163f670f31f974c99108bf7040c704adc15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Tue, 24 Jun 2025 10:00:35 +0200 Subject: [PATCH 47/59] NGSTACK-977 rename MoveTagsType form to MultiselectTagsType form and add 'show_parent_field' option to the form --- ...veTagsType.php => MultiselectTagsType.php} | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) rename bundle/Form/Type/{MoveTagsType.php => MultiselectTagsType.php} (56%) diff --git a/bundle/Form/Type/MoveTagsType.php b/bundle/Form/Type/MultiselectTagsType.php similarity index 56% rename from bundle/Form/Type/MoveTagsType.php rename to bundle/Form/Type/MultiselectTagsType.php index 9590a2fb..4078ec92 100644 --- a/bundle/Form/Type/MoveTagsType.php +++ b/bundle/Form/Type/MultiselectTagsType.php @@ -10,7 +10,7 @@ use function array_map; -final class MoveTagsType extends AbstractType +final class MultiselectTagsType extends AbstractType { public function configureOptions(OptionsResolver $resolver): void { @@ -27,22 +27,26 @@ public function configureOptions(OptionsResolver $resolver): void } return true; - }); + }) + ->setDefault('show_parent_field', true) + ->setAllowedTypes('show_parent_field', 'bool'); } public function buildForm(FormBuilderInterface $builder, array $options): void { - $builder - ->add( - 'parentTag', - TagTreeType::class, - [ - 'label' => 'tag.parent_tag', - 'disableSubtree' => array_map( - static fn (Tag $tag): int => $tag->id, - $options['tags'], - ), - ], - ); + if ($options['show_parent_field'] === true) { + $builder + ->add( + 'parentTag', + TagTreeType::class, + [ + 'label' => 'tag.parent_tag', + 'disableSubtree' => array_map( + static fn (Tag $tag): int => $tag->id, + $options['tags'], + ), + ], + ); + } } } From 07866bc4feadfbbf5d17788e975d2ba06a68826f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Tue, 24 Jun 2025 10:04:45 +0200 Subject: [PATCH 48/59] NGSTACK-977 update hideTagsAction and revealTagsAction methods in TagController to use MultiselectTagsType form and render new templates --- bundle/Controller/Admin/TagController.php | 75 ++++++++++++++++--- .../translations/netgen_tags_admin.en.yml | 6 ++ .../translations/netgen_tags_admin.fr.yml | 11 ++- .../views/admin/tag/hide_tags.html.twig | 43 +++++++++++ .../views/admin/tag/reveal_tags.html.twig | 43 +++++++++++ 5 files changed, 165 insertions(+), 13 deletions(-) create mode 100644 bundle/Resources/views/admin/tag/hide_tags.html.twig create mode 100644 bundle/Resources/views/admin/tag/reveal_tags.html.twig diff --git a/bundle/Controller/Admin/TagController.php b/bundle/Controller/Admin/TagController.php index 221125e9..458a5e70 100644 --- a/bundle/Controller/Admin/TagController.php +++ b/bundle/Controller/Admin/TagController.php @@ -11,7 +11,7 @@ use Netgen\TagsBundle\Core\Pagination\Pagerfanta\SearchTagsAdapter; use Netgen\TagsBundle\Form\Type\CopyTagsType; use Netgen\TagsBundle\Form\Type\LanguageSelectType; -use Netgen\TagsBundle\Form\Type\MoveTagsType; +use Netgen\TagsBundle\Form\Type\MultiselectTagsType; use Netgen\TagsBundle\Form\Type\TagConvertType; use Netgen\TagsBundle\Form\Type\TagCreateType; use Netgen\TagsBundle\Form\Type\TagMergeType; @@ -594,13 +594,14 @@ public function moveTagsAction(Request $request, ?Tag $parentTag = null): Respon } $form = $this->createForm( - MoveTagsType::class, + MultiselectTagsType::class, [ 'parentTag' => $parentTag instanceof Tag ? $parentTag->id : 0, ], [ 'tags' => $tags, 'action' => $request->getPathInfo(), + 'show_parent_field' => true, ], ); @@ -754,13 +755,38 @@ public function hideTagsAction(Request $request, ?Tag $parentTag = null): Respon $tags[] = $this->tagsService->loadTag((int) $tagId); } - foreach ($tags as $tagObject) { - $this->tagsService->hideTag($tagObject); - } + $form = $this->createForm( + MultiselectTagsType::class, + [ + 'parentTag' => $parentTag instanceof Tag ? $parentTag->id : 0, + ], + [ + 'tags' => $tags, + 'action' => $request->getPathInfo(), + 'show_parent_field' => false, + ], + ); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + foreach ($tags as $tagObject) { + $this->tagsService->hideTag($tagObject); + } - $this->addFlashMessage('success', 'tags_hidden'); + $this->addFlashMessage('success', 'tags_hidden'); - return $this->redirectToTag($parentTag); + return $this->redirectToTag($parentTag); + } + + return $this->render( + '@NetgenTags/admin/tag/hide_tags.html.twig', + [ + 'parentTag' => $parentTag, + 'tags' => $tags, + 'form' => $form->createView(), + ], + ); } public function revealTagsAction(Request $request, ?Tag $parentTag = null): Response @@ -781,13 +807,38 @@ public function revealTagsAction(Request $request, ?Tag $parentTag = null): Resp $tags[] = $this->tagsService->loadTag((int) $tagId); } - foreach ($tags as $tagObject) { - $this->tagsService->revealTag($tagObject); - } + $form = $this->createForm( + MultiselectTagsType::class, + [ + 'parentTag' => $parentTag instanceof Tag ? $parentTag->id : 0, + ], + [ + 'tags' => $tags, + 'action' => $request->getPathInfo(), + 'show_parent_field' => false, + ], + ); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + foreach ($tags as $tagObject) { + $this->tagsService->revealTag($tagObject); + } - $this->addFlashMessage('success', 'tags_revealed'); + $this->addFlashMessage('success', 'tags_revealed'); - return $this->redirectToTag($parentTag); + return $this->redirectToTag($parentTag); + } + + return $this->render( + '@NetgenTags/admin/tag/reveal_tags.html.twig', + [ + 'parentTag' => $parentTag, + 'tags' => $tags, + 'form' => $form->createView(), + ], + ); } public function searchTagsAction(Request $request): Response diff --git a/bundle/Resources/translations/netgen_tags_admin.en.yml b/bundle/Resources/translations/netgen_tags_admin.en.yml index a94832cb..855dd7ec 100644 --- a/bundle/Resources/translations/netgen_tags_admin.en.yml +++ b/bundle/Resources/translations/netgen_tags_admin.en.yml @@ -87,6 +87,12 @@ tag.copy_tags.title: 'Copy tags' tag.delete_tags.title: 'Delete tags' tag.delete_tags.message: 'Are you sure you want to delete the selected tags? All children tags and synonyms will also be deleted and removed from existing objects.' +tag.hide_tags.title: 'Hide tags' +tag.hide_tags.message: 'Are you sure you want to hide the selected tags?' + +tag.reveal_tags.title: 'Reveal tags' +tag.reveal_tags.message: 'Are you sure you want to reveal the selected tags?' + tag.button.save: 'Save' tag.button.discard: 'Discard' tag.button.yes: 'Yes' diff --git a/bundle/Resources/translations/netgen_tags_admin.fr.yml b/bundle/Resources/translations/netgen_tags_admin.fr.yml index 1cdd615c..6c19744e 100644 --- a/bundle/Resources/translations/netgen_tags_admin.fr.yml +++ b/bundle/Resources/translations/netgen_tags_admin.fr.yml @@ -62,8 +62,11 @@ tag.add_synonym.title: 'Ajouter un synonyme' tag.convert.title: 'Convertir en synonyme' -tag.hide.title: 'Cacher le tag' +tag.hide.title: 'Hide tag' +tag.hide.message: 'Êtes-vous sûr de vouloir cacher la balise "%tagKeyword%"? Toutes les balises descendantes qui ne sont pas explicitement cachées deviendront alors invisibles et marquées comme "cachées par le parent".' + tag.reveal.title: 'Révéler le tag' +tag.reveal.message: "Êtes-vous sûr de vouloir révéler la balise '%tagKeyword%' ? Toutes ses balises descendantes redeviendront visibles, à l'exception de celles qui sont explicitement cachées ou qui ont un autre ancêtre caché." tag.move_tags.title: 'Déplacer les tags' tag.move_tags.message: 'Êtes-vous sûr de vouloir déplacer les tags sélectionnés ?' @@ -73,6 +76,12 @@ tag.copy_tags.title: 'Copier les tags' tag.delete_tags.title: 'Supprimer les tags' tag.delete_tags.message: 'Êtes-vous sûr de vouloir supprimer les tags sélectionnés ? Tous les tag et synonymes enfants seront également supprimés et supprimés des objets existants.' +tag.hide_tags.title: 'Cacher les tags' +tag.hide_tags.message: 'Êtes-vous sûr de vouloir masquer les balises sélectionnées?' + +tag.reveal_tags.title: 'Révéler les tags' +tag.reveal_tags.message: 'Êtes-vous sûr de vouloir révéler les balises sélectionnées?' + tag.button.save: 'Sauvegarder' tag.button.discard: 'Jeter' tag.button.yes: 'Oui' diff --git a/bundle/Resources/views/admin/tag/hide_tags.html.twig b/bundle/Resources/views/admin/tag/hide_tags.html.twig new file mode 100644 index 00000000..21970691 --- /dev/null +++ b/bundle/Resources/views/admin/tag/hide_tags.html.twig @@ -0,0 +1,43 @@ +{% extends netgen_tags_admin.pageLayoutTemplate %} + +{% trans_default_domain 'netgen_tags_admin' %} + +{% form_theme form '@NetgenTags/form/tags.html.twig' %} + +{% block content %} +

{{ 'tag.hide_tags.title'|trans }}

+ +

{{ 'tag.hide_tags.message'|trans }}

+ + {{ form_start(form) }} + + + + + + + + + {% for tag in tags %} + + + + {% endfor %} + +
{{ 'tag.title'|trans }}
+ + {% if parentTag is not null %}{{ parentTag.keyword }} / {% endif %}{{ tag.keyword }} +
+ + {{ form_widget(form) }} + +
+ + + + {{ 'tag.button.discard'|trans }} + +
+ {{ form_end(form) }} + +{% endblock %} diff --git a/bundle/Resources/views/admin/tag/reveal_tags.html.twig b/bundle/Resources/views/admin/tag/reveal_tags.html.twig new file mode 100644 index 00000000..4b4e10f1 --- /dev/null +++ b/bundle/Resources/views/admin/tag/reveal_tags.html.twig @@ -0,0 +1,43 @@ +{% extends netgen_tags_admin.pageLayoutTemplate %} + +{% trans_default_domain 'netgen_tags_admin' %} + +{% form_theme form '@NetgenTags/form/tags.html.twig' %} + +{% block content %} +

{{ 'tag.reveal_tags.title'|trans }}

+ +

{{ 'tag.reveal_tags.message'|trans }}

+ + {{ form_start(form) }} + + + + + + + + + {% for tag in tags %} + + + + {% endfor %} + +
{{ 'tag.title'|trans }}
+ + {% if parentTag is not null %}{{ parentTag.keyword }} / {% endif %}{{ tag.keyword }} +
+ + {{ form_widget(form) }} + +
+ + + + {{ 'tag.button.discard'|trans }} + +
+ {{ form_end(form) }} + +{% endblock %} From 535890e6d374eabd5ed6416213d2098ccb3c5471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Tue, 24 Jun 2025 10:23:06 +0200 Subject: [PATCH 49/59] NGSTACK-977 add 'autocomplete_provide_hidden_tags' parameter to the configTreeBuilder and contextualize it --- bundle/DependencyInjection/Configuration.php | 4 ++++ bundle/DependencyInjection/NetgenTagsExtension.php | 1 + 2 files changed, 5 insertions(+) diff --git a/bundle/DependencyInjection/Configuration.php b/bundle/DependencyInjection/Configuration.php index cd0e9f05..5b77ca7d 100644 --- a/bundle/DependencyInjection/Configuration.php +++ b/bundle/DependencyInjection/Configuration.php @@ -159,6 +159,10 @@ public function getConfigTreeBuilder(): TreeBuilder ->booleanNode('show_hidden_tags') ->info('Whether to show hidden tags or not') ->defaultTrue() + ->end() + ->booleanNode('autocomplete_provide_hidden_tags') + ->info('When searching for a tag to add it to some content, should autocomplete show hidden tags or not') + ->defaultFalse() ->end(); return $treeBuilder; diff --git a/bundle/DependencyInjection/NetgenTagsExtension.php b/bundle/DependencyInjection/NetgenTagsExtension.php index 5fb3090c..df1b7f8d 100644 --- a/bundle/DependencyInjection/NetgenTagsExtension.php +++ b/bundle/DependencyInjection/NetgenTagsExtension.php @@ -123,6 +123,7 @@ static function (array $config, string $scope, ContextualizerInterface $c): void $c->setContextualParameter('field.autocomplete_limit', $scope, $config['field']['autocomplete_limit']); $c->setContextualParameter('show_hidden_tags', $scope, $config['show_hidden_tags']); + $c->setContextualParameter('autocomplete_provide_hidden_tags', $scope, $config['autocomplete_provide_hidden_tags']); }, ); From 96279be1f19e95ea907223050479cd429fc5fa78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Tue, 24 Jun 2025 10:24:07 +0200 Subject: [PATCH 50/59] NGSTACK-977 modify autoCompleteAction() method in FieldController to look at 'autocomplete_provide_hidden_tags' config parameter --- bundle/Controller/Admin/FieldController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundle/Controller/Admin/FieldController.php b/bundle/Controller/Admin/FieldController.php index e7221b68..4e0b74da 100644 --- a/bundle/Controller/Admin/FieldController.php +++ b/bundle/Controller/Admin/FieldController.php @@ -40,7 +40,7 @@ public function autoCompleteAction(Request $request): JsonResponse true, 0, -1, - false, + $this->configResolver->getParameter('autocomplete_provide_hidden_tags', 'netgen_tags'), ); $data = $data = $this->filterTags($searchResult->tags, $subTreeLimit, $hideRootTag); From 9a00e4ed9ad5bba7c03fcf6295eb273572d6b0f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 26 Jun 2025 09:52:26 +0200 Subject: [PATCH 51/59] NGSTACK-977 make autocomplete suggestions not show invisible tags when searching to add a tag to some content --- .../Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index c564d2c2..c5fd5175 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -212,7 +212,7 @@ public function getTagsByKeyword(string $keyword, string $translation, bool $use if ($showHiddenTags !== null && $showHiddenTags === false) { $tagIdsQuery->andWhere( - $tagIdsQuery->expr()->neq('is_hidden', '1'), + $tagIdsQuery->expr()->neq('is_invisible', '1'), ); } @@ -251,7 +251,7 @@ public function getTagsByKeyword(string $keyword, string $translation, bool $use if ($showHiddenTags !== null && $showHiddenTags === false) { $query->andWhere( - $query->expr()->neq('is_hidden', '1'), + $query->expr()->neq('is_invisible', '1'), ); } @@ -274,7 +274,7 @@ public function getTagsByKeywordCount(string $keyword, string $translation, bool if ($showHiddenTags !== null && $showHiddenTags === false) { $query->andWhere( - $query->expr()->neq('is_hidden', '1'), + $query->expr()->neq('is_invisible', '1'), ); } From cf15dfc158c4d067f090e9a84182f96eacb769d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 26 Jun 2025 09:53:10 +0200 Subject: [PATCH 52/59] NGSTACK-977 add data about tag visibility when searching for tags in Netgen Tags adminUI --- bundle/Resources/views/admin/tag/search.html.twig | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bundle/Resources/views/admin/tag/search.html.twig b/bundle/Resources/views/admin/tag/search.html.twig index 969823f4..b46519a5 100644 --- a/bundle/Resources/views/admin/tag/search.html.twig +++ b/bundle/Resources/views/admin/tag/search.html.twig @@ -51,7 +51,16 @@ {% for tag in pager %} {{ tag.id }} - {{ tag.keyword }} + + + {{ tag.keyword }} + {% if tag.isHidden %} + ({{ 'tag.hidden'|trans|lower }}) + {% elseif tag.isInvisible %} + ({{ 'tag.hidden_by_parent'|trans }}) + {% endif %} + + {% if tag.hasParent() %} {% set parentTagKeyword = netgen_tags_tag_keyword(tag.parentTagId) %} From fd4e11fb902dad1e17e091e0328a145bbfc899dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 26 Jun 2025 11:36:03 +0200 Subject: [PATCH 53/59] NGSTACK-977 fix tag converting to synonym process and merging process and add the ability to select hidden tags in those processes --- bundle/API/Repository/TagsService.php | 2 ++ .../Legacy/Tags/Gateway/DoctrineDatabase.php | 4 ++++ bundle/Resources/public/admin/js/app.js | 15 ++++++++++++--- bundle/Resources/views/admin/tree.html.twig | 1 + 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/bundle/API/Repository/TagsService.php b/bundle/API/Repository/TagsService.php index d9b76dff..7a0e8ac5 100644 --- a/bundle/API/Repository/TagsService.php +++ b/bundle/API/Repository/TagsService.php @@ -222,6 +222,8 @@ public function addSynonym(SynonymCreateStruct $synonymCreateStruct): Tag; /** * Converts $tag to a synonym of $mainTag. * + * If $tag was hidden, it will remain hidden after converting + * * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException If either of specified tags is not found * @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException If the current user is not allowed to convert tag to synonym * @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidArgumentException If either one of the tags is a synonym diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index c5fd5175..61264ba8 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -680,6 +680,10 @@ public function convertToSynonym(int $tagId, array $mainTagData): void ->setParameter('depth', $mainTagData['depth'], Types::INTEGER) ->setParameter('path_string', $this->getSynonymPathString($tagId, $mainTagData['path_string']), Types::STRING); + if ($mainTagData['is_hidden'] === 0 && $mainTagData['is_invisible'] === 1) { + $query->set('is_invisible', '0'); + } + $query->execute(); } diff --git a/bundle/Resources/public/admin/js/app.js b/bundle/Resources/public/admin/js/app.js index cafb7bd8..72bf709e 100644 --- a/bundle/Resources/public/admin/js/app.js +++ b/bundle/Resources/public/admin/js/app.js @@ -79,6 +79,8 @@ jQuery.noConflict(); } } }).on("open_node.jstree", function (event, data) { + var route = self.$tree.data('route'); + if (self.disableSubtree !== '') { self.disableNode(self.disableSubtree); } @@ -87,7 +89,9 @@ jQuery.noConflict(); data.node.original && (data.node.original.hidden === true || data.node.original.invisible === true)) { - self.disableNode(data.node.id); + if (['netgen_tags_admin_tag_convert', 'netgen_tags_admin_tag_merge'].indexOf(route) === -1) { + self.disableNode(data.node.id); + } } if (data.node && data.node.children) { @@ -97,12 +101,15 @@ jQuery.noConflict(); childNode.original && (childNode.original.hidden === true || childNode.original.invisible === true)) { - self.disableNode(childId); + if (['netgen_tags_admin_tag_convert', 'netgen_tags_admin_tag_merge'].indexOf(route) === -1) { + self.disableNode(childId); + } } }); } }).on('click', '.jstree-anchor', function (event) { var selectedNode = $(this).jstree(true).get_node($(this)); + var route = self.$tree.data('route'); if (self.disableSubtree !== '') { self.disableSubtree = self.disableSubtree.toString().split(','); @@ -126,7 +133,9 @@ jQuery.noConflict(); if (selectedNode.original && (selectedNode.original.hidden === true || selectedNode.original.invisible === true)) { - return false; + if (['netgen_tags_admin_tag_convert', 'netgen_tags_admin_tag_merge'].indexOf(route) === -1) { + return false; + } } self.$el.find('input.tag-id').val(selectedNode.id); diff --git a/bundle/Resources/views/admin/tree.html.twig b/bundle/Resources/views/admin/tree.html.twig index 9f68e8d6..c390c904 100644 --- a/bundle/Resources/views/admin/tree.html.twig +++ b/bundle/Resources/views/admin/tree.html.twig @@ -13,5 +13,6 @@ data-showRootTag="{{ showRootTag ? 'true' : 'false' }}" data-selectedTagPath="{{ selectedTag ? selectedTag.pathString : '' }}" data-disableSubtree="{{ disableSubtree|join(',') }}" + data-route="{{ app.request.get('_route') }}" > {% endblock %} From c81ccefb58a8dd9c9e39171738e03f338a3630b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 26 Jun 2025 11:36:37 +0200 Subject: [PATCH 54/59] NGSTACK-977 remove dump statements from 'hide' and 'reveal' twig templates --- bundle/Resources/views/admin/tag/hide.html.twig | 2 -- bundle/Resources/views/admin/tag/reveal.html.twig | 2 -- 2 files changed, 4 deletions(-) diff --git a/bundle/Resources/views/admin/tag/hide.html.twig b/bundle/Resources/views/admin/tag/hide.html.twig index 21b3aa58..09906feb 100644 --- a/bundle/Resources/views/admin/tag/hide.html.twig +++ b/bundle/Resources/views/admin/tag/hide.html.twig @@ -7,8 +7,6 @@

{{ 'tag.hide.message'|trans({'%tagKeyword%': tag.keyword}) }}

- {% dump(tag) %} -
diff --git a/bundle/Resources/views/admin/tag/reveal.html.twig b/bundle/Resources/views/admin/tag/reveal.html.twig index a8d77b64..2eeaf08e 100644 --- a/bundle/Resources/views/admin/tag/reveal.html.twig +++ b/bundle/Resources/views/admin/tag/reveal.html.twig @@ -7,8 +7,6 @@

{{ 'tag.reveal.message'|trans({'%tagKeyword%': tag.keyword}) }}

- {% dump(tag) %} - From 45cf8e6b0357f29f629986840603787dac0b6076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 26 Jun 2025 11:50:18 +0200 Subject: [PATCH 55/59] NGSTACK-977 update 'is_hidden' check to 'is_invisible' check in methods that have showHiddenTags as parameter in DoctrineDatabase --- .../Legacy/Tags/Gateway/DoctrineDatabase.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index 61264ba8..5c8f7526 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -132,7 +132,7 @@ public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array if ($showHiddenTags !== null && $showHiddenTags === false) { $tagIdsQuery->andWhere( - $tagIdsQuery->expr()->neq('is_hidden', '1'), + $tagIdsQuery->expr()->neq('is_invisible', '1'), ); } @@ -164,7 +164,7 @@ public function getChildren(int $tagId, int $offset = 0, int $limit = -1, ?array if ($showHiddenTags !== null && $showHiddenTags === false) { $query->andWhere( - $query->expr()->neq('is_hidden', '1'), + $query->expr()->neq('is_invisible', '1'), ); } @@ -186,7 +186,7 @@ public function getChildrenCount(int $tagId, ?array $translations = null, bool $ if ($showHiddenTags !== null && $showHiddenTags === false) { $query->andWhere( - $query->expr()->neq('is_hidden', '1'), + $query->expr()->neq('is_invisible', '1'), ); } @@ -305,7 +305,7 @@ public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array if ($showHiddenTags !== null && $showHiddenTags === false) { $tagIdsQuery->andWhere( - $tagIdsQuery->expr()->neq('is_hidden', '1'), + $tagIdsQuery->expr()->neq('is_invisible', '1'), ); } @@ -333,7 +333,7 @@ public function getSynonyms(int $tagId, int $offset = 0, int $limit = -1, ?array if ($showHiddenTags !== null && $showHiddenTags === false) { $query->andWhere( - $query->expr()->neq('is_hidden', '1'), + $query->expr()->neq('is_invisible', '1'), ); } @@ -353,7 +353,7 @@ public function getSynonymCount(int $tagId, ?array $translations = null, bool $u if ($showHiddenTags !== null && $showHiddenTags === false) { $query->andWhere( - $query->expr()->neq('is_hidden', '1'), + $query->expr()->neq('is_invisible', '1'), ); } From 50a4c290ff07e9441ac7074ae9420ec3f263281c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 26 Jun 2025 11:51:28 +0200 Subject: [PATCH 56/59] NGSTACK-977 fix revealing a hidden synonym by checking the 'main_tag_id' property --- .../Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php index 5c8f7526..8ff19be7 100644 --- a/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php +++ b/bundle/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabase.php @@ -948,7 +948,7 @@ public function revealTag(int $tagId): void array_pop($pathArray); $shouldRemainInvisible = false; - if ($pathArray !== []) { + if ($pathArray !== [] && $basicTagData['main_tag_id'] === 0) { $query = $this->connection->createQueryBuilder(); $query ->select('COUNT(id)') From 40605b929127e28ada2d43c2096631e6d5b0249c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 26 Jun 2025 11:55:54 +0200 Subject: [PATCH 57/59] NGSTACK-977 update testConvertToSynonym to check 'is_invisible' property --- .../Legacy/Tags/Gateway/DoctrineDatabaseTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabaseTest.php b/tests/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabaseTest.php index 748bc0ed..f561f081 100644 --- a/tests/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabaseTest.php +++ b/tests/Core/Persistence/Legacy/Tags/Gateway/DoctrineDatabaseTest.php @@ -718,16 +718,18 @@ public function testConvertToSynonym(): void 'parent_id' => 7, 'depth' => 3, 'path_string' => '/8/7/40/', + 'is_hidden' => 0, + 'is_invisible' => 1, ], ); $query = $this->connection->createQueryBuilder(); self::assertQueryResult( [ - [80, 7, 40, 'fetch', 3, '/8/7/80/'], + [80, 7, 40, 'fetch', 3, '/8/7/80/', 0], ], $query - ->select('id', 'parent_id', 'main_tag_id', 'keyword', 'depth', 'path_string') + ->select('id', 'parent_id', 'main_tag_id', 'keyword', 'depth', 'path_string', 'is_invisible') ->from('eztags') ->where($query->expr()->eq('id', 80)), ); From 88fc80e98642ae270a857d9a3ba4c0da2bcfcb0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 26 Jun 2025 13:50:31 +0200 Subject: [PATCH 58/59] NGSTACK-977 add some missing translations for french langauge --- bundle/Resources/translations/netgen_tags_admin.fr.yml | 2 +- .../Resources/translations/netgen_tags_admin_flash.fr.yml | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/bundle/Resources/translations/netgen_tags_admin.fr.yml b/bundle/Resources/translations/netgen_tags_admin.fr.yml index 6c19744e..33b42ed5 100644 --- a/bundle/Resources/translations/netgen_tags_admin.fr.yml +++ b/bundle/Resources/translations/netgen_tags_admin.fr.yml @@ -62,7 +62,7 @@ tag.add_synonym.title: 'Ajouter un synonyme' tag.convert.title: 'Convertir en synonyme' -tag.hide.title: 'Hide tag' +tag.hide.title: 'Cacher le tag' tag.hide.message: 'Êtes-vous sûr de vouloir cacher la balise "%tagKeyword%"? Toutes les balises descendantes qui ne sont pas explicitement cachées deviendront alors invisibles et marquées comme "cachées par le parent".' tag.reveal.title: 'Révéler le tag' diff --git a/bundle/Resources/translations/netgen_tags_admin_flash.fr.yml b/bundle/Resources/translations/netgen_tags_admin_flash.fr.yml index da2fb94c..43269767 100644 --- a/bundle/Resources/translations/netgen_tags_admin_flash.fr.yml +++ b/bundle/Resources/translations/netgen_tags_admin_flash.fr.yml @@ -8,10 +8,14 @@ success.tag_added: 'Le nouveau tag "%tagKeyword%" a été créé' success.tag_updated: 'Le tag "%tagKeyword%" a été mis à jour' success.tag_deleted: 'Le tag "%tagKeyword%" a été supprimé' success.tag_merged: 'Le tag "%tagKeyword%" a été fusionné avec le tag "%sourceTagKeyword%"' -success.tag_converted: 'Tag "%tagKeyword%" has been converted to synonym of tag "%mainTagKeyword%"' +success.tag_converted: 'Le tag "%tagKeyword%" a été converti en synonyme du tag "%mainTagKeyword%"' success.tags_moved: 'Les tags ont été déplacés avec succès' success.tags_copied: 'Les tags ont été copiés avec succès' success.tags_deleted: 'Les tags ont été supprimées avec succès' +success.tags_hidden: 'Les étiquettes ont été masquées avec succès' +success.tags_revealed: 'Les étiquettes ont été révélées avec succès' success.translation_removed: 'La traduction de la locale "%locale%" a été supprimée avec succès' success.main_translation_set: 'La traduction pour la locale "%locale%" a été définie comme nouvelle traduction principale' success.always_available_set: 'Le drapeau Toujours disponible a été mis à jour avec succès.' +success.tag_hidden: 'Le tag "%tagKeyword%" a été caché' +success.tag_revealed: 'Le tag "%tagKeyword%" a été révélé' From 71a91025f867df4c18495736f8cb022f0ffacfbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ante=20Prka=C4=8Din?= Date: Thu, 26 Jun 2025 15:12:55 +0200 Subject: [PATCH 59/59] NGSTACK-977 change policies to only have one for hiding and revealing --- bundle/Controller/Admin/TagController.php | 6 +++--- bundle/Core/Repository/TagsService.php | 14 +++----------- bundle/Resources/config/policies.yaml | 3 --- .../Resources/views/admin/tag/children.html.twig | 4 ---- bundle/Resources/views/admin/tag/show.html.twig | 10 ++++++---- 5 files changed, 12 insertions(+), 25 deletions(-) diff --git a/bundle/Controller/Admin/TagController.php b/bundle/Controller/Admin/TagController.php index 458a5e70..fdc47bdf 100644 --- a/bundle/Controller/Admin/TagController.php +++ b/bundle/Controller/Admin/TagController.php @@ -523,7 +523,7 @@ public function childrenAction(Request $request, ?Tag $tag = null): Response public function hideAction(Request $request, Tag $tag): Response { - $this->denyAccessUnlessGranted('ibexa:tags:hide' . ($tag->isSynonym() ? 'synonym' : '')); + $this->denyAccessUnlessGranted('ibexa:tags:hide'); if ($request->request->has('HideTagButton')) { if (!$this->isCsrfTokenValid('netgen_tags_admin', (string) ($request->request->get('_csrf_token') ?? ''))) { @@ -549,7 +549,7 @@ public function hideAction(Request $request, Tag $tag): Response public function revealAction(Request $request, Tag $tag): Response { - $this->denyAccessUnlessGranted('ibexa:tags:reveal' . ($tag->isSynonym() ? 'synonym' : '')); + $this->denyAccessUnlessGranted('ibexa:tags:hide'); if ($request->request->has('RevealTagButton')) { if (!$this->isCsrfTokenValid('netgen_tags_admin', (string) ($request->request->get('_csrf_token') ?? ''))) { @@ -791,7 +791,7 @@ public function hideTagsAction(Request $request, ?Tag $parentTag = null): Respon public function revealTagsAction(Request $request, ?Tag $parentTag = null): Response { - $this->denyAccessUnlessGranted('ibexa:tags:reveal'); + $this->denyAccessUnlessGranted('ibexa:tags:hide'); $tagIds = (array) $request->request->get( 'Tags', diff --git a/bundle/Core/Repository/TagsService.php b/bundle/Core/Repository/TagsService.php index 6a2a36bc..0bcbe569 100644 --- a/bundle/Core/Repository/TagsService.php +++ b/bundle/Core/Repository/TagsService.php @@ -758,11 +758,7 @@ public function newTagUpdateStruct(): TagUpdateStruct public function hideTag(Tag $tag): void { - if ($tag->mainTagId > 0) { - if ($this->hasAccess('tags', 'hidesynonym') === false) { - throw new UnauthorizedException('tags', 'hidesynonym'); - } - } elseif ($this->hasAccess('tags', 'hide') === false) { + if ($this->hasAccess('tags', 'hide') === false) { throw new UnauthorizedException('tags', 'hide'); } @@ -780,12 +776,8 @@ public function hideTag(Tag $tag): void public function revealTag(Tag $tag): void { - if ($tag->mainTagId > 0) { - if ($this->hasAccess('tags', 'revealsynonym') === false) { - throw new UnauthorizedException('tags', 'revealsynonym'); - } - } elseif ($this->hasAccess('tags', 'reveal') === false) { - throw new UnauthorizedException('tags', 'reveal'); + if ($this->hasAccess('tags', 'hide') === false) { + throw new UnauthorizedException('tags', 'hide'); } $this->repository->beginTransaction(); diff --git a/bundle/Resources/config/policies.yaml b/bundle/Resources/config/policies.yaml index 991cac7f..4e76fe98 100644 --- a/bundle/Resources/config/policies.yaml +++ b/bundle/Resources/config/policies.yaml @@ -10,6 +10,3 @@ tags: makesynonym: ~ merge: ~ hide: ~ - reveal: ~ - hidesynonym: ~ - revealsynonym: ~ diff --git a/bundle/Resources/views/admin/tag/children.html.twig b/bundle/Resources/views/admin/tag/children.html.twig index 8e060ffc..66ba0f0f 100644 --- a/bundle/Resources/views/admin/tag/children.html.twig +++ b/bundle/Resources/views/admin/tag/children.html.twig @@ -6,7 +6,6 @@ {% set can_edit = is_granted('ibexa:tags:edit') %} {% set can_delete = is_granted('ibexa:tags:delete') %} {% set can_hide = is_granted('ibexa:tags:hide') %} -{% set can_reveal = is_granted('ibexa:tags:reveal') %}

{{ 'tag.children.title'|trans }} ({{ childrenTags|length }})

@@ -87,9 +86,6 @@ {% if can_hide %} - {% endif %} - - {% if can_reveal %} {% endif %} diff --git a/bundle/Resources/views/admin/tag/show.html.twig b/bundle/Resources/views/admin/tag/show.html.twig index 580d49d8..c2394e69 100644 --- a/bundle/Resources/views/admin/tag/show.html.twig +++ b/bundle/Resources/views/admin/tag/show.html.twig @@ -45,10 +45,12 @@ {% endif %} {% endif %} - {% if is_granted('ibexa:tags:hide' ~ (tag.isSynonym ? 'synonym' : '')) and not tag.isHidden %} - {{ 'tag.hide.title'|trans }} - {% elseif is_granted('ibexa:tags:reveal' ~ (tag.isSynonym ? 'synonym' : '')) and tag.isHidden %} - {{ 'tag.reveal.title'|trans }} + {% if is_granted('ibexa:tags:hide') %} + {% if not tag.isHidden %} + {{ 'tag.hide.title'|trans }} + {% else %} + {{ 'tag.reveal.title'|trans }} + {% endif %} {% endif %}