Skip to content

Commit e15eb8b

Browse files
authored
Merge pull request #54863 from nextcloud/backport/54810/stable32
[stable32] feat(SystemTag): Add typed events for tag mapper events
2 parents eee5f28 + c7b5031 commit e15eb8b

File tree

6 files changed

+193
-0
lines changed

6 files changed

+193
-0
lines changed

lib/composer/composer/autoload_classmap.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,8 +848,10 @@
848848
'OCP\\SystemTag\\MapperEvent' => $baseDir . '/lib/public/SystemTag/MapperEvent.php',
849849
'OCP\\SystemTag\\SystemTagsEntityEvent' => $baseDir . '/lib/public/SystemTag/SystemTagsEntityEvent.php',
850850
'OCP\\SystemTag\\TagAlreadyExistsException' => $baseDir . '/lib/public/SystemTag/TagAlreadyExistsException.php',
851+
'OCP\\SystemTag\\TagAssignedEvent' => $baseDir . '/lib/public/SystemTag/TagAssignedEvent.php',
851852
'OCP\\SystemTag\\TagCreationForbiddenException' => $baseDir . '/lib/public/SystemTag/TagCreationForbiddenException.php',
852853
'OCP\\SystemTag\\TagNotFoundException' => $baseDir . '/lib/public/SystemTag/TagNotFoundException.php',
854+
'OCP\\SystemTag\\TagUnassignedEvent' => $baseDir . '/lib/public/SystemTag/TagUnassignedEvent.php',
853855
'OCP\\SystemTag\\TagUpdateForbiddenException' => $baseDir . '/lib/public/SystemTag/TagUpdateForbiddenException.php',
854856
'OCP\\Talk\\Exceptions\\NoBackendException' => $baseDir . '/lib/public/Talk/Exceptions/NoBackendException.php',
855857
'OCP\\Talk\\IBroker' => $baseDir . '/lib/public/Talk/IBroker.php',

lib/composer/composer/autoload_static.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,8 +889,10 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
889889
'OCP\\SystemTag\\MapperEvent' => __DIR__ . '/../../..' . '/lib/public/SystemTag/MapperEvent.php',
890890
'OCP\\SystemTag\\SystemTagsEntityEvent' => __DIR__ . '/../../..' . '/lib/public/SystemTag/SystemTagsEntityEvent.php',
891891
'OCP\\SystemTag\\TagAlreadyExistsException' => __DIR__ . '/../../..' . '/lib/public/SystemTag/TagAlreadyExistsException.php',
892+
'OCP\\SystemTag\\TagAssignedEvent' => __DIR__ . '/../../..' . '/lib/public/SystemTag/TagAssignedEvent.php',
892893
'OCP\\SystemTag\\TagCreationForbiddenException' => __DIR__ . '/../../..' . '/lib/public/SystemTag/TagCreationForbiddenException.php',
893894
'OCP\\SystemTag\\TagNotFoundException' => __DIR__ . '/../../..' . '/lib/public/SystemTag/TagNotFoundException.php',
895+
'OCP\\SystemTag\\TagUnassignedEvent' => __DIR__ . '/../../..' . '/lib/public/SystemTag/TagUnassignedEvent.php',
894896
'OCP\\SystemTag\\TagUpdateForbiddenException' => __DIR__ . '/../../..' . '/lib/public/SystemTag/TagUpdateForbiddenException.php',
895897
'OCP\\Talk\\Exceptions\\NoBackendException' => __DIR__ . '/../../..' . '/lib/public/Talk/Exceptions/NoBackendException.php',
896898
'OCP\\Talk\\IBroker' => __DIR__ . '/../../..' . '/lib/public/Talk/IBroker.php',

lib/private/SystemTag/SystemTagObjectMapper.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
use OCP\SystemTag\ISystemTagManager;
1818
use OCP\SystemTag\ISystemTagObjectMapper;
1919
use OCP\SystemTag\MapperEvent;
20+
use OCP\SystemTag\TagAssignedEvent;
2021
use OCP\SystemTag\TagNotFoundException;
22+
use OCP\SystemTag\TagUnassignedEvent;
2123

2224
class SystemTagObjectMapper implements ISystemTagObjectMapper {
2325
public const RELATION_TABLE = 'systemtag_object_mapping';
@@ -172,6 +174,7 @@ public function assignTags(string $objId, string $objectType, $tagIds): void {
172174
$objId,
173175
$tagsAssigned
174176
));
177+
$this->dispatcher->dispatchTyped(new TagAssignedEvent($objectType, [$objId], $tagsAssigned));
175178
}
176179

177180
/**
@@ -202,6 +205,7 @@ public function unassignTags(string $objId, string $objectType, $tagIds): void {
202205
$objId,
203206
$tagIds
204207
));
208+
$this->dispatcher->dispatchTyped(new TagUnassignedEvent($objectType, [$objId], $tagIds));
205209
}
206210

207211
/**
@@ -307,6 +311,9 @@ public function setObjectIdsForTag(string $tagId, string $objectType, array $obj
307311
[(int)$tagId]
308312
));
309313
}
314+
if (!empty($removedObjectIds)) {
315+
$this->dispatcher->dispatchTyped(new TagUnassignedEvent($objectType, array_map(fn ($objectId) => (string)$objectId, $removedObjectIds), [(int)$tagId]));
316+
}
310317

311318
if (empty($objectIds)) {
312319
return;
@@ -338,6 +345,9 @@ public function setObjectIdsForTag(string $tagId, string $objectType, array $obj
338345
[(int)$tagId]
339346
));
340347
}
348+
if (!empty($addedObjectIds)) {
349+
$this->dispatcher->dispatchTyped(new TagAssignedEvent($objectType, array_map(fn ($objectId) => (string)$objectId, $addedObjectIds), [(int)$tagId]));
350+
}
341351

342352
// Dispatch unassign events for removed object ids
343353
foreach ($removedObjectIds as $objectId) {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
6+
* SPDX-License-Identifier: AGPL-3.0-or-later
7+
*/
8+
namespace OCP\SystemTag;
9+
10+
use OCP\EventDispatcher\Event;
11+
use OCP\EventDispatcher\IWebhookCompatibleEvent;
12+
13+
/**
14+
* Event class for when a system tag is assigned to an object
15+
*
16+
* @since 32.0.0
17+
*/
18+
class TagAssignedEvent extends Event implements IWebhookCompatibleEvent {
19+
protected string $objectType;
20+
/** @var list<string> */
21+
protected array $objectIds;
22+
/** @var list<int> */
23+
protected array $tags;
24+
25+
/**
26+
* constructor
27+
*
28+
* @param list<string> $objectIds
29+
* @param list<int> $tags
30+
* @since 32.0.0
31+
*/
32+
public function __construct(string $objectType, array $objectIds, array $tags) {
33+
parent::__construct();
34+
$this->objectType = $objectType;
35+
$this->objectIds = $objectIds;
36+
$this->tags = $tags;
37+
}
38+
39+
/**
40+
* @since 32.0.0
41+
*/
42+
public function getObjectType(): string {
43+
return $this->objectType;
44+
}
45+
46+
/**
47+
* @return list<string>
48+
* @since 32.0.0
49+
*/
50+
public function getObjectIds(): array {
51+
return $this->objectIds;
52+
}
53+
54+
/**
55+
* @return list<int>
56+
* @since 32.0.0
57+
*/
58+
public function getTags(): array {
59+
return $this->tags;
60+
}
61+
62+
/**
63+
* @return array{objectType: string, objectIds: list<string>, tagIds: list<int>}
64+
* @since 32.0.0
65+
*/
66+
public function getWebhookSerializable(): array {
67+
return [
68+
'objectType' => $this->getObjectType(),
69+
'objectIds' => $this->getObjectIds(),
70+
'tagIds' => $this->getTags(),
71+
];
72+
}
73+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
6+
* SPDX-License-Identifier: AGPL-3.0-or-later
7+
*/
8+
namespace OCP\SystemTag;
9+
10+
use OCP\EventDispatcher\Event;
11+
use OCP\EventDispatcher\IWebhookCompatibleEvent;
12+
13+
/**
14+
* Event class for when a system tag is unassigned from an object
15+
*
16+
* @since 32.0.0
17+
*/
18+
class TagUnassignedEvent extends Event implements IWebhookCompatibleEvent {
19+
protected string $objectType;
20+
/** @var list<string> */
21+
protected array $objectIds;
22+
/** @var list<int> */
23+
protected array $tags;
24+
25+
/**
26+
* constructor
27+
*
28+
* @param list<string> $objectIds
29+
* @param list<int> $tags
30+
* @since 32.0.0
31+
*/
32+
public function __construct(string $objectType, array $objectIds, array $tags) {
33+
parent::__construct();
34+
$this->objectType = $objectType;
35+
$this->objectIds = $objectIds;
36+
$this->tags = $tags;
37+
}
38+
39+
/**
40+
* @since 32.0.0
41+
*/
42+
public function getObjectType(): string {
43+
return $this->objectType;
44+
}
45+
46+
/**
47+
* @return list<string>
48+
* @since 32.0.0
49+
*/
50+
public function getObjectIds(): array {
51+
return $this->objectIds;
52+
}
53+
54+
/**
55+
* @return list<int>
56+
* @since 32.0.0
57+
*/
58+
public function getTags(): array {
59+
return $this->tags;
60+
}
61+
62+
/**
63+
* @return array{objectType: string, objectIds: list<string>, tagIds: list<int>}
64+
* @since 32.0.0
65+
*/
66+
public function getWebhookSerializable(): array {
67+
return [
68+
'objectType' => $this->getObjectType(),
69+
'objectIds' => $this->getObjectIds(),
70+
'tagIds' => $this->getTags(),
71+
];
72+
}
73+
}

tests/lib/SystemTag/SystemTagObjectMapperTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@
1111
use OC\SystemTag\SystemTag;
1212
use OC\SystemTag\SystemTagManager;
1313
use OC\SystemTag\SystemTagObjectMapper;
14+
use OCP\EventDispatcher\Event;
1415
use OCP\EventDispatcher\IEventDispatcher;
1516
use OCP\IDBConnection;
1617
use OCP\Server;
1718
use OCP\SystemTag\ISystemTag;
1819
use OCP\SystemTag\ISystemTagManager;
1920
use OCP\SystemTag\ISystemTagObjectMapper;
21+
use OCP\SystemTag\TagAssignedEvent;
2022
use OCP\SystemTag\TagNotFoundException;
23+
use OCP\SystemTag\TagUnassignedEvent;
2124
use Test\TestCase;
2225

2326
/**
@@ -208,16 +211,46 @@ public function testGetObjectsForNonExistingTag(): void {
208211
}
209212

210213
public function testAssignUnassignTags(): void {
214+
$event = null;
215+
$this->dispatcher->expects($this->any())->method('dispatchTyped')->willReturnCallback(function (Event $e) use (&$event) {
216+
$event = $e;
217+
});
218+
211219
$this->tagMapper->unassignTags('1', 'testtype', [$this->tag1->getId()]);
212220

221+
$this->assertNotNull($event);
222+
$this->assertEquals(TagUnassignedEvent::class, $event::class);
223+
$this->assertEquals('testtype', $event->getObjectType());
224+
$this->assertCount(1, $event->getObjectIds());
225+
$this->assertEquals('1', current($event->getObjectIds()));
226+
$this->assertCount(1, $event->getTags());
227+
$this->assertEquals($this->tag1->getId(), current($event->getTags()));
228+
213229
$tagIdMapping = $this->tagMapper->getTagIdsForObjects('1', 'testtype');
214230
$this->assertEquals([
215231
1 => [$this->tag2->getId()],
216232
], $tagIdMapping);
217233

218234
$this->tagMapper->assignTags('1', 'testtype', [$this->tag1->getId()]);
235+
236+
$this->assertNotNull($event);
237+
$this->assertEquals(TagAssignedEvent::class, $event::class);
238+
$this->assertEquals('testtype', $event->getObjectType());
239+
$this->assertCount(1, $event->getObjectIds());
240+
$this->assertEquals('1', current($event->getObjectIds()));
241+
$this->assertCount(1, $event->getTags());
242+
$this->assertEquals($this->tag1->getId(), current($event->getTags()));
243+
219244
$this->tagMapper->assignTags('1', 'testtype', $this->tag3->getId());
220245

246+
$this->assertNotNull($event);
247+
$this->assertEquals(TagAssignedEvent::class, $event::class);
248+
$this->assertEquals('testtype', $event->getObjectType());
249+
$this->assertCount(1, $event->getObjectIds());
250+
$this->assertEquals('1', current($event->getObjectIds()));
251+
$this->assertCount(1, $event->getTags());
252+
$this->assertEquals($this->tag3->getId(), current($event->getTags()));
253+
221254
$tagIdMapping = $this->tagMapper->getTagIdsForObjects('1', 'testtype');
222255

223256
$this->assertEquals([

0 commit comments

Comments
 (0)