The old one was deprecated in 22.0.0 but didn't had a replacement. Signed-off-by: Carl Schwan <carlschwan@kde.org>pull/58602/head
parent
351d3c6377
commit
b42ebea5fc
@ -1,28 +0,0 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/*! |
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors |
||||
* SPDX-License-Identifier: AGPL-3.0-or-later |
||||
*/ |
||||
|
||||
namespace OCA\AdminAudit\Actions; |
||||
|
||||
use OCP\SystemTag\ISystemTag; |
||||
|
||||
class TagManagement extends Action { |
||||
/** |
||||
* @param ISystemTag $tag newly created tag |
||||
*/ |
||||
public function createTag(ISystemTag $tag): void { |
||||
$this->log('System tag "%s" (%s, %s) created', |
||||
[ |
||||
'name' => $tag->getName(), |
||||
'visibility' => $tag->isUserVisible() ? 'visible' : 'invisible', |
||||
'assignable' => $tag->isUserAssignable() ? 'user assignable' : 'system only', |
||||
], |
||||
['name', 'visibility', 'assignable'] |
||||
); |
||||
} |
||||
} |
||||
@ -0,0 +1,40 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH |
||||
* SPDX-FileContributor: Carl Schwan |
||||
* SPDX-License-Identifier: AGPL-3.0-or-later |
||||
*/ |
||||
|
||||
namespace OCA\AdminAudit\Listener; |
||||
|
||||
use OCA\AdminAudit\Actions\Action; |
||||
use OCP\EventDispatcher\Event; |
||||
use OCP\EventDispatcher\IEventListener; |
||||
use OCP\SystemTag\Events\TagCreatedEvent; |
||||
use Override; |
||||
|
||||
/** |
||||
* @template-implements IEventListener<TagCreatedEvent> |
||||
*/ |
||||
class TagEventListener extends Action implements IEventListener { |
||||
#[Override] |
||||
public function handle(Event $event): void { |
||||
if (!$event instanceof TagCreatedEvent) { |
||||
return; |
||||
} |
||||
|
||||
$tag = $event->getTag(); |
||||
|
||||
$this->log('System tag "%s" (%s, %s) created', |
||||
[ |
||||
'name' => $tag->getName(), |
||||
'visibility' => $tag->isUserVisible() ? 'visible' : 'invisible', |
||||
'assignable' => $tag->isUserAssignable() ? 'user assignable' : 'system only', |
||||
], |
||||
['name', 'visibility', 'assignable'] |
||||
); |
||||
} |
||||
} |
||||
@ -1,222 +0,0 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors |
||||
* SPDX-FileCopyrightText: 2016 ownCloud, Inc. |
||||
* SPDX-License-Identifier: AGPL-3.0-only |
||||
*/ |
||||
|
||||
namespace OCA\SystemTags\Activity; |
||||
|
||||
use OCP\Activity\IManager; |
||||
use OCP\App\IAppManager; |
||||
use OCP\Files\Config\IMountProviderCollection; |
||||
use OCP\Files\IRootFolder; |
||||
use OCP\Files\Node; |
||||
use OCP\IConfig; |
||||
use OCP\IGroup; |
||||
use OCP\IGroupManager; |
||||
use OCP\IUser; |
||||
use OCP\IUserSession; |
||||
use OCP\Share\IShareHelper; |
||||
use OCP\SystemTag\ISystemTag; |
||||
use OCP\SystemTag\ISystemTagManager; |
||||
use OCP\SystemTag\ManagerEvent; |
||||
use OCP\SystemTag\MapperEvent; |
||||
use OCP\SystemTag\TagNotFoundException; |
||||
|
||||
class Listener { |
||||
/** |
||||
* Listener constructor. |
||||
* |
||||
* @param IGroupManager $groupManager |
||||
* @param IManager $activityManager |
||||
* @param IUserSession $session |
||||
* @param IConfig $config |
||||
* @param ISystemTagManager $tagManager |
||||
* @param IAppManager $appManager |
||||
* @param IMountProviderCollection $mountCollection |
||||
* @param IRootFolder $rootFolder |
||||
* @param IShareHelper $shareHelper |
||||
*/ |
||||
public function __construct( |
||||
protected IGroupManager $groupManager, |
||||
protected IManager $activityManager, |
||||
protected IUserSession $session, |
||||
protected IConfig $config, |
||||
protected ISystemTagManager $tagManager, |
||||
protected IAppManager $appManager, |
||||
protected IMountProviderCollection $mountCollection, |
||||
protected IRootFolder $rootFolder, |
||||
protected IShareHelper $shareHelper, |
||||
) { |
||||
} |
||||
|
||||
/** |
||||
* @param ManagerEvent $event |
||||
*/ |
||||
public function event(ManagerEvent $event) { |
||||
$actor = $this->session->getUser(); |
||||
if ($actor instanceof IUser) { |
||||
$actor = $actor->getUID(); |
||||
} else { |
||||
$actor = ''; |
||||
} |
||||
$tag = $event->getTag(); |
||||
|
||||
$activity = $this->activityManager->generateEvent(); |
||||
$activity->setApp('systemtags') |
||||
->setType('systemtags') |
||||
->setAuthor($actor) |
||||
->setObject('systemtag', (int)$tag->getId(), $tag->getName()); |
||||
if ($event->getEvent() === ManagerEvent::EVENT_CREATE) { |
||||
$activity->setSubject(Provider::CREATE_TAG, [ |
||||
$actor, |
||||
$this->prepareTagAsParameter($event->getTag()), |
||||
]); |
||||
} elseif ($event->getEvent() === ManagerEvent::EVENT_UPDATE) { |
||||
$activity->setSubject(Provider::UPDATE_TAG, [ |
||||
$actor, |
||||
$this->prepareTagAsParameter($event->getTag()), |
||||
$this->prepareTagAsParameter($event->getTagBefore()), |
||||
]); |
||||
} elseif ($event->getEvent() === ManagerEvent::EVENT_DELETE) { |
||||
$activity->setSubject(Provider::DELETE_TAG, [ |
||||
$actor, |
||||
$this->prepareTagAsParameter($event->getTag()), |
||||
]); |
||||
} else { |
||||
return; |
||||
} |
||||
|
||||
$group = $this->groupManager->get('admin'); |
||||
if ($group instanceof IGroup) { |
||||
foreach ($group->getUsers() as $user) { |
||||
$activity->setAffectedUser($user->getUID()); |
||||
$this->activityManager->publish($activity); |
||||
} |
||||
} |
||||
|
||||
if ($actor !== '' && ($event->getEvent() === ManagerEvent::EVENT_CREATE || $event->getEvent() === ManagerEvent::EVENT_UPDATE)) { |
||||
$this->updateLastUsedTags($actor, $event->getTag()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @param MapperEvent $event |
||||
*/ |
||||
public function mapperEvent(MapperEvent $event) { |
||||
$tagIds = $event->getTags(); |
||||
if ($event->getObjectType() !== 'files' || empty($tagIds) |
||||
|| !in_array($event->getEvent(), [MapperEvent::EVENT_ASSIGN, MapperEvent::EVENT_UNASSIGN]) |
||||
|| !$this->appManager->isEnabledForAnyone('activity')) { |
||||
// System tags not for files, no tags, not (un-)assigning or no activity-app enabled (save the energy) |
||||
return; |
||||
} |
||||
|
||||
try { |
||||
$tags = $this->tagManager->getTagsByIds($tagIds); |
||||
} catch (TagNotFoundException $e) { |
||||
// User assigned/unassigned a non-existing tag, ignore... |
||||
return; |
||||
} |
||||
|
||||
if (empty($tags)) { |
||||
return; |
||||
} |
||||
|
||||
// Get all mount point owners |
||||
$cache = $this->mountCollection->getMountCache(); |
||||
$mounts = $cache->getMountsForFileId($event->getObjectId()); |
||||
if (empty($mounts)) { |
||||
return; |
||||
} |
||||
|
||||
$users = []; |
||||
foreach ($mounts as $mount) { |
||||
$owner = $mount->getUser()->getUID(); |
||||
$ownerFolder = $this->rootFolder->getUserFolder($owner); |
||||
$nodes = $ownerFolder->getById($event->getObjectId()); |
||||
if (!empty($nodes)) { |
||||
/** @var Node $node */ |
||||
$node = array_shift($nodes); |
||||
$al = $this->shareHelper->getPathsForAccessList($node); |
||||
$users += $al['users']; |
||||
} |
||||
} |
||||
|
||||
$actor = $this->session->getUser(); |
||||
if ($actor instanceof IUser) { |
||||
$actor = $actor->getUID(); |
||||
} else { |
||||
$actor = ''; |
||||
} |
||||
|
||||
$activity = $this->activityManager->generateEvent(); |
||||
$activity->setApp('systemtags') |
||||
->setType('systemtags') |
||||
->setAuthor($actor) |
||||
->setObject($event->getObjectType(), (int)$event->getObjectId()); |
||||
|
||||
foreach ($users as $user => $path) { |
||||
$user = (string)$user; // numerical ids could be ints which are not accepted everywhere |
||||
$activity->setAffectedUser($user); |
||||
|
||||
foreach ($tags as $tag) { |
||||
// don't publish activity for non-admins if tag is invisible |
||||
if (!$tag->isUserVisible() && !$this->groupManager->isAdmin($user)) { |
||||
continue; |
||||
} |
||||
if ($event->getEvent() === MapperEvent::EVENT_ASSIGN) { |
||||
$activity->setSubject(Provider::ASSIGN_TAG, [ |
||||
$actor, |
||||
$path, |
||||
$this->prepareTagAsParameter($tag), |
||||
]); |
||||
} elseif ($event->getEvent() === MapperEvent::EVENT_UNASSIGN) { |
||||
$activity->setSubject(Provider::UNASSIGN_TAG, [ |
||||
$actor, |
||||
$path, |
||||
$this->prepareTagAsParameter($tag), |
||||
]); |
||||
} |
||||
|
||||
$this->activityManager->publish($activity); |
||||
} |
||||
} |
||||
|
||||
if ($actor !== '' && $event->getEvent() === MapperEvent::EVENT_ASSIGN) { |
||||
foreach ($tags as $tag) { |
||||
$this->updateLastUsedTags($actor, $tag); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @param string $actor |
||||
* @param ISystemTag $tag |
||||
*/ |
||||
protected function updateLastUsedTags($actor, ISystemTag $tag) { |
||||
$lastUsedTags = $this->config->getUserValue($actor, 'systemtags', 'last_used', '[]'); |
||||
$lastUsedTags = json_decode($lastUsedTags, true); |
||||
|
||||
array_unshift($lastUsedTags, $tag->getId()); |
||||
$lastUsedTags = array_unique($lastUsedTags); |
||||
$lastUsedTags = array_slice($lastUsedTags, 0, 10); |
||||
|
||||
$this->config->setUserValue($actor, 'systemtags', 'last_used', json_encode($lastUsedTags)); |
||||
} |
||||
|
||||
/** |
||||
* @param ISystemTag $tag |
||||
* @return string |
||||
*/ |
||||
protected function prepareTagAsParameter(ISystemTag $tag) { |
||||
return json_encode([ |
||||
'id' => $tag->getId(), |
||||
'name' => $tag->getName(), |
||||
'assignable' => $tag->isUserAssignable(), |
||||
'visible' => $tag->isUserVisible(), |
||||
]); |
||||
} |
||||
} |
||||
@ -0,0 +1,218 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors |
||||
* SPDX-FileCopyrightText: 2016 ownCloud, Inc. |
||||
* SPDX-License-Identifier: AGPL-3.0-only |
||||
*/ |
||||
|
||||
namespace OCA\SystemTags\Activity; |
||||
|
||||
use OCP\Activity\IManager; |
||||
use OCP\App\IAppManager; |
||||
use OCP\Config\IUserConfig; |
||||
use OCP\EventDispatcher\Event; |
||||
use OCP\EventDispatcher\IEventListener; |
||||
use OCP\Files\Config\IMountProviderCollection; |
||||
use OCP\Files\IRootFolder; |
||||
use OCP\Files\Node; |
||||
use OCP\IGroup; |
||||
use OCP\IGroupManager; |
||||
use OCP\IUser; |
||||
use OCP\IUserSession; |
||||
use OCP\Share\IShareHelper; |
||||
use OCP\SystemTag\Events\AbstractTagEvent; |
||||
use OCP\SystemTag\Events\TagCreatedEvent; |
||||
use OCP\SystemTag\Events\TagDeletedEvent; |
||||
use OCP\SystemTag\Events\TagUpdatedEvent; |
||||
use OCP\SystemTag\ISystemTag; |
||||
use OCP\SystemTag\ISystemTagManager; |
||||
use OCP\SystemTag\TagAssignedEvent; |
||||
use OCP\SystemTag\TagNotFoundException; |
||||
use OCP\SystemTag\TagUnassignedEvent; |
||||
use Override; |
||||
|
||||
/** |
||||
* @template-implements IEventListener<TagAssignedEvent|TagUnassignedEvent|TagUpdatedEvent|TagCreatedEvent|TagDeletedEvent> |
||||
*/ |
||||
class TagListener implements IEventListener { |
||||
public function __construct( |
||||
private readonly IGroupManager $groupManager, |
||||
private readonly IManager $activityManager, |
||||
private readonly IUserSession $session, |
||||
private readonly IUserConfig $userConfig, |
||||
private readonly ISystemTagManager $tagManager, |
||||
private readonly IAppManager $appManager, |
||||
private readonly IMountProviderCollection $mountCollection, |
||||
private readonly IRootFolder $rootFolder, |
||||
private readonly IShareHelper $shareHelper, |
||||
) { |
||||
} |
||||
|
||||
#[Override] |
||||
public function handle(Event $event): void { |
||||
if ($event instanceof AbstractTagEvent) { |
||||
$this->handleManagerEvent($event); |
||||
} elseif ($event instanceof TagAssignedEvent || $event instanceof TagUnassignedEvent) { |
||||
$this->handleTagEvent($event); |
||||
} |
||||
} |
||||
|
||||
private function handleManagerEvent(AbstractTagEvent $event): void { |
||||
if (!$this->appManager->isEnabledForAnyone('activity')) { |
||||
return; |
||||
} |
||||
|
||||
$actor = $this->session->getUser(); |
||||
if ($actor instanceof IUser) { |
||||
$actor = $actor->getUID(); |
||||
} else { |
||||
$actor = ''; |
||||
} |
||||
$tag = $event->getTag(); |
||||
|
||||
$activity = $this->activityManager->generateEvent(); |
||||
$activity->setApp('systemtags') |
||||
->setType('systemtags') |
||||
->setAuthor($actor) |
||||
->setObject('systemtag', (int)$tag->getId(), $tag->getName()); |
||||
if ($event instanceof TagCreatedEvent) { |
||||
$activity->setSubject(Provider::CREATE_TAG, [ |
||||
$actor, |
||||
$this->prepareTagAsParameter($event->getTag()), |
||||
]); |
||||
} elseif ($event instanceof TagUpdatedEvent) { |
||||
$activity->setSubject(Provider::UPDATE_TAG, [ |
||||
$actor, |
||||
$this->prepareTagAsParameter($event->getTag()), |
||||
$this->prepareTagAsParameter($event->getTagBefore()), |
||||
]); |
||||
} elseif ($event instanceof TagDeletedEvent) { |
||||
$activity->setSubject(Provider::DELETE_TAG, [ |
||||
$actor, |
||||
$this->prepareTagAsParameter($event->getTag()), |
||||
]); |
||||
} else { |
||||
return; |
||||
} |
||||
|
||||
$group = $this->groupManager->get('admin'); |
||||
if ($group instanceof IGroup) { |
||||
foreach ($group->getUsers() as $user) { |
||||
$activity->setAffectedUser($user->getUID()); |
||||
$this->activityManager->publish($activity); |
||||
} |
||||
} |
||||
|
||||
if ($actor !== '' && ($event instanceof TagCreatedEvent || $event instanceof TagUpdatedEvent)) { |
||||
$this->updateLastUsedTags($actor, $event->getTag()); |
||||
} |
||||
} |
||||
|
||||
private function handleTagEvent(TagAssignedEvent|TagUnassignedEvent $event) { |
||||
$tagIds = $event->getTags(); |
||||
if ($event->getObjectType() !== 'files' || empty($tagIds) |
||||
|| !$this->appManager->isEnabledForAnyone('activity')) { |
||||
// System tags not for files, no tags, not (un-)assigning or no activity-app enabled (save the energy) |
||||
return; |
||||
} |
||||
|
||||
try { |
||||
$tags = $this->tagManager->getTagsByIds($tagIds); |
||||
} catch (TagNotFoundException $e) { |
||||
// User assigned/unassigned a non-existing tag, ignore... |
||||
return; |
||||
} |
||||
|
||||
if (empty($tags)) { |
||||
return; |
||||
} |
||||
|
||||
// Get all mount point owners |
||||
$cache = $this->mountCollection->getMountCache(); |
||||
foreach ($event->getObjectIds() as $objectId) { |
||||
$mounts = $cache->getMountsForFileId((int)$objectId); |
||||
if (empty($mounts)) { |
||||
continue; |
||||
} |
||||
|
||||
$users = []; |
||||
foreach ($mounts as $mount) { |
||||
$owner = $mount->getUser()->getUID(); |
||||
$ownerFolder = $this->rootFolder->getUserFolder($owner); |
||||
$nodes = $ownerFolder->getById((int)$objectId); |
||||
if (!empty($nodes)) { |
||||
/** @var Node $node */ |
||||
$node = array_shift($nodes); |
||||
$al = $this->shareHelper->getPathsForAccessList($node); |
||||
$users += $al['users']; |
||||
} |
||||
} |
||||
|
||||
$actor = $this->session->getUser(); |
||||
if ($actor instanceof IUser) { |
||||
$actor = $actor->getUID(); |
||||
} else { |
||||
$actor = ''; |
||||
} |
||||
|
||||
$activity = $this->activityManager->generateEvent(); |
||||
$activity->setApp('systemtags') |
||||
->setType('systemtags') |
||||
->setAuthor($actor) |
||||
->setObject($event->getObjectType(), (int)$objectId); |
||||
|
||||
foreach ($users as $user => $path) { |
||||
$user = (string)$user; // numerical ids could be ints which are not accepted everywhere |
||||
$activity->setAffectedUser($user); |
||||
|
||||
foreach ($tags as $tag) { |
||||
// don't publish activity for non-admins if tag is invisible |
||||
if (!$tag->isUserVisible() && !$this->groupManager->isAdmin($user)) { |
||||
continue; |
||||
} |
||||
if ($event instanceof TagAssignedEvent) { |
||||
$activity->setSubject(Provider::ASSIGN_TAG, [ |
||||
$actor, |
||||
$path, |
||||
$this->prepareTagAsParameter($tag), |
||||
]); |
||||
} else { |
||||
$activity->setSubject(Provider::UNASSIGN_TAG, [ |
||||
$actor, |
||||
$path, |
||||
$this->prepareTagAsParameter($tag), |
||||
]); |
||||
} |
||||
|
||||
$this->activityManager->publish($activity); |
||||
} |
||||
} |
||||
|
||||
if ($actor !== '' && $event instanceof TagAssignedEvent) { |
||||
foreach ($tags as $tag) { |
||||
$this->updateLastUsedTags($actor, $tag); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected function updateLastUsedTags(string $actor, ISystemTag $tag): void { |
||||
$lastUsedTags = $this->userConfig->getValueArray($actor, 'systemtags', 'last_used'); |
||||
|
||||
array_unshift($lastUsedTags, $tag->getId()); |
||||
$lastUsedTags = array_unique($lastUsedTags); |
||||
$lastUsedTags = array_slice($lastUsedTags, 0, 10); |
||||
|
||||
$this->userConfig->setValueArray($actor, 'systemtags', 'last_used', $lastUsedTags); |
||||
} |
||||
|
||||
protected function prepareTagAsParameter(ISystemTag $tag): string { |
||||
return json_encode([ |
||||
'id' => $tag->getId(), |
||||
'name' => $tag->getName(), |
||||
'assignable' => $tag->isUserAssignable(), |
||||
'visible' => $tag->isUserVisible(), |
||||
], flags: JSON_THROW_ON_ERROR); |
||||
} |
||||
} |
||||
@ -0,0 +1,38 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors |
||||
* SPDX-License-Identifier: AGPL-3.0-or-later |
||||
*/ |
||||
|
||||
namespace OCP\SystemTag\Events; |
||||
|
||||
use OCP\AppFramework\Attribute\Consumable; |
||||
use OCP\EventDispatcher\Event; |
||||
use OCP\SystemTag\ISystemTag; |
||||
|
||||
/** |
||||
* Abstract event related to the lifecycle of a tag. |
||||
* |
||||
* @since 35.0.0 |
||||
*/ |
||||
#[Consumable(since: '35.0.0')] |
||||
abstract class AbstractTagEvent extends Event { |
||||
/** |
||||
* AbstractTagEvent constructor |
||||
* @since 35.0.0 |
||||
*/ |
||||
public function __construct( |
||||
private readonly ISystemTag $tag, |
||||
) { |
||||
} |
||||
|
||||
/** |
||||
* @since 35.0.0 |
||||
*/ |
||||
public function getTag(): ISystemTag { |
||||
return $this->tag; |
||||
} |
||||
} |
||||
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors |
||||
* SPDX-License-Identifier: AGPL-3.0-or-later |
||||
*/ |
||||
|
||||
namespace OCP\SystemTag\Events; |
||||
|
||||
use OCP\AppFramework\Attribute\Consumable; |
||||
|
||||
/** |
||||
* Event triggered when creating a new tag. |
||||
* |
||||
* @since 35.0.0 |
||||
*/ |
||||
#[Consumable(since: '35.0.0')] |
||||
class TagCreatedEvent extends AbstractTagEvent { |
||||
} |
||||
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors |
||||
* SPDX-License-Identifier: AGPL-3.0-or-later |
||||
*/ |
||||
|
||||
namespace OCP\SystemTag\Events; |
||||
|
||||
use OCP\AppFramework\Attribute\Consumable; |
||||
|
||||
/** |
||||
* Event triggered when deleting a new tag. |
||||
* |
||||
* @since 35.0.0 |
||||
*/ |
||||
#[Consumable(since: '35.0.0')] |
||||
class TagDeletedEvent extends AbstractTagEvent { |
||||
} |
||||
@ -0,0 +1,42 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH |
||||
* SPDX-FileContributor: Carl Schwan |
||||
* SPDX-License-Identifier: AGPL-3.0-or-later |
||||
*/ |
||||
|
||||
namespace OCP\SystemTag\Events; |
||||
|
||||
use OCP\AppFramework\Attribute\Consumable; |
||||
use OCP\SystemTag\ISystemTag; |
||||
|
||||
/** |
||||
* Event triggered when updated a tag. |
||||
* |
||||
* @since 35.0.0 |
||||
*/ |
||||
#[Consumable(since: '35.0.0')] |
||||
class TagUpdatedEvent extends AbstractTagEvent { |
||||
/** |
||||
* TagUpdatedEvent constructor |
||||
* @since 35.0.0 |
||||
*/ |
||||
public function __construct( |
||||
ISystemTag $tag, |
||||
private readonly ISystemTag $beforeTag, |
||||
) { |
||||
parent::__construct($tag); |
||||
} |
||||
|
||||
/** |
||||
* Return the tag state before it was updated. |
||||
* |
||||
* @since 35.0.0 |
||||
*/ |
||||
public function getTagBefore(): ISystemTag { |
||||
return $this->beforeTag; |
||||
} |
||||
} |
||||
Loading…
Reference in new issue