silverstripe/versioned-snapshots

SilverStripe版本化快照

安装量: 12,309

依赖关系: 1

建议者: 0

安全性: 0

星标: 13

关注者: 11

分支: 12

开放性问题: 16

类型:silverstripe-vendormodule

1.0.1 2023-10-11 00:44 UTC

README

Build Status Latest Stable Version Total Downloads Latest Unstable Version License PHP Version Require

概述

启用快照,以增强深层嵌套所有者结构的版本历史和修改状态。它解决了版本化中的一个重要用户体验问题,这在内容块实现中尤其明显。

此模块启用快照的数据模型。要充分利用其核心功能,您应该安装silverstripe/versioned-snapshot-admin,通过CMS的“历史”选项卡公开这些快照。

警告:此模块是实验性的,不被认为是稳定的。

安装

$ composer require silverstripe/versioned-snapshots

您还需要运行dev/build

这是做什么的?

假设您有一个依赖于所有者结构的内容模型,使用$owns设置。

BlockPage
  (has_many) Blocks
    (has_one) Gallery
       (many_many) Image

每个节点之间的所有者关系允许通过一条命令(或点击按钮)发布整个图。但用户不清楚哪些所有者内容(如果有的话)将被发布。如果相册被修改,BlockPage将不会显示修改后的状态。

此模块旨在使这些修改状态和隐式编辑历史更加透明。

做什么?

目前,不支持回滚拥有其他内容的记录,并将产生意外结果。此外,不支持比较父版本的两次版本之间的所有者更改。

我可以在我的当前项目中使用这个吗?

是的,但有几点要注意

  • many_many关系必须使用“通过”对象(隐式many_many不可版本化)。
  • 您必须将所有版本化内容迁移到快照中(请参阅从版本化迁移)。
  • 某些编辑事件可能无法捕获,尤其是第三方模块提供的某些事件。请参阅(添加您自己的快照创建器
  • 它(目前)与Postgres不完全兼容。欢迎提交拉取请求!

API

虽然SnapshotPublishable扩展提供了大量的API接口,但只有少数几个主要方法是针对最终用户的

  • $myDataObject->hasOwnedModifications(): bool如果记录拥有已更改的记录返回true
  • $myDataObject->getPublishableObjects(): ArrayList返回一个与所有者一起发布的DataObject实例列表
  • $myDataObject->getActivityFeed(): ArrayList提供了一组可以在模板上渲染的对象,以创建可读的活动流。返回一个包含以下内容的ActivityEntry对象数组
    • Subject:触发活动的DataObject记录
    • Action:以下之一:CREATEDMODIFIEDDELETEDADDEDREMOVED
    • Owner:仅在many_many关系定义中。提供有关记录链接到什么的详细信息。通知ADDEDREMOVED操作。

扩展

快照功能是通过SnapshotPublishable扩展提供的,该扩展是RecursivePublishable的替代品。默认情况下,此模块将用这个自定义子类替换添加到所有数据对象中的RecursivePublishable

工作原理

快照是在CMS中由silverstripe/cms-events模块触发的用户事件所注册的处理程序创建的。

自定义快照消息

默认情况下,这些事件将触发语言文件中定义的消息,例如:_t('SilverStripe\Snapshots\Handler\Form\FormSubmissionHandler.HANDLER_publish', 'Publish page')。然而,如果您想在此配置级别自定义此消息,只需在处理程序类中覆盖消息即可。

SilverStripe\Snapshots\Handler\Form\FormSubmissionHandler:
  messages:
    publish: 'My publish message'

在这种情况下,“publish”是动作标识符(处理表单的函数)。

自定义现有快照创建者

所有处理程序都由注入器注册,因此自定义它们的最简单方法是覆盖配置中的定义。

例如,如果您在页面保存时需要自定义与快照相关的内容

use SilverStripe\Snapshots\Handler\Form\SaveHandler;
use SilverStripe\EventDispatcher\Event\EventContextInterface;
use SilverStripe\Snapshots\Snapshot;

class MySaveHandler extends SaveHandler
{
    protected function createSnapshot(EventContextInterface $context): ?Snapshot
    {
        //...
    }
}
SilverStripe\Core\Injector\Injector:
  SilverStripe\Snapshots\Handler\Form\SaveHandler:
    class: MyProject\MySaveHandler

添加自己的快照创建者

如果您已将自定义动作或表单处理程序添加到CMS中,您可能希望确保它们被默认快照创建者跟踪,或者甚至为它们构建自己的快照创建者。在这种情况下,您可以使用Dispatcher的声明性API来订阅您需要的事件。

假设我们有一个提交到函数的表单:public function myFormHandler($data, $form)

SilverStripe\Core\Injector\Injector:
  SilverStripe\Snapshots\Dispatch\Dispatcher:
    properties:
      handlers:
        myForm:
          on:
            - 'formSubmitted.myFormHandler'
          handler: %$MyProject\Handlers\MyHandler

注意,事件名称是配置键的一部分。这使得另一个配置层能够禁用它。请参见以下内容。

移除快照创建者

要从一个处理程序中移除事件,只需将其添加到off数组中。

SilverStripe\Core\Injector\Injector:
  SilverStripe\Snapshots\Dispatch\Dispatcher:
    properties:
      handlers:
        myForm:
          off:
            - 'formSubmitted.myFormHandler'

程序化添加事件处理程序

您可以将EventHandlerLoader实现注册到Dispatcher,以程序化注册和注销事件。

SilverStripe\Core\Injector\Injector:
  SilverStripe\Snapshots\Dispatch\Dispatcher:
    properties:
      loaders:
        myLoader: %$MyProject\MyEventLoader
use SilverStripe\Snapshots\Dispatch\DispatcherLoaderInterface;
use SilverStripe\Snapshots\Dispatch\Dispatcher;
use SilverStripe\Snapshots\Handler\Form\SaveHandler;

class MyEventLoader implements DispatcherLoaderInterface
{
    public function addToDispatcher(Dispatcher $dispatcher): void
    {
        $dispatcher->removeListenerByClassName('formSubmitted.save', SaveHandler::class);
    }
}

快照创建API

为了涵盖所有情况,此模块允许您在代码中的任何部分调用快照创建,而无需正常动作流程。

当您想要创建快照时,只需像这样调用createSnapshot函数

Snapshot::singleton()->createSnapshot(DataObject $origin, array $extraObjects = []);

$origin是要匹配动作的对象,即动作正在更改原始对象。

$extraObjects是您希望在快照中的额外数据对象数组。每次调用createSnapshot都会隐式包括以下记录,除了原始记录外

  • 原始记录“拥有”的所有记录,例如:BlockImage > BaseElement > ElementalArea > Page
  • 原始记录隐式修改的所有记录。(见隐式修改

没有“原始记录”时

对您的内容的一些修改不一定是由编辑特定实体的编辑事件触发的。对于这些情况,您可以使用createSnapshotFromEvent API。

Snapshot::singleton()->createSnapshotFromEvent('Description of event');

通用事件的示例包括重新排列网站树、复制翻译、导入内容等。将其视为您内容的简单“git提交”消息。它为您的时间线创建了一个标记,内容编辑员可以在未来的某个时间点引用。

隐式修改

有时对看似“原始”记录的编辑实际上是其他记录的隐式编辑。这种情况最常见的情况是添加相关记录。例如,如果用户更改了管理many_many关系的CheckboxSetField,则显示这些复选框的记录保持不变,并不需要新的版本。但是,添加或删除新相关记录则值得创建一个新的快照,因为所有权链已更新。

createSnapshot API知道这类修改,并尝试使用RelationDiffer服务来检测它们。当一个修改包括对关系的更改时,createSnapshot将回退到创建一个通用事件来描述发生了什么更改,例如:'添加了两个类别'

这种关系差异比较昂贵,每次保存每个关系时都需要运行,因此,您需要通过$snapshot_relation_tracking设置来启用它。

class Product extends DataObject
{
    private static $many_many = [
        'Categories' => Category::class,
    ];

    private static $snapshot_relation_tracking = ['Categories'];

}

另一个隐式修改的常见例子是 silverstripe-elemental 版本 4.x 中的 ElementalEditor 字段。当页面保存时,它实际上保存了编辑器中的所有块,这些块是 has_many 关系。因为它是一个如此常见的用例,所以块默认情况下会通过 snapshot_relation_tracking 跟踪,这样页面保存就会产生适当的“修改/添加/删除块”快照。

从 Versioned 迁移

要迁移所有您的 _versions 表到快照,请使用 snapshot-migration 任务

$ vendor/bin/sake dev/tasks/snapshot-migration

或者,此任务作为 排队作业 提供。

此任务的影响应该相当小,因为它只写入新的(可能为空的)快照表。它应该能够扩展,因为它不对PHP中的记录进行处理。迁移是纯SQL。

第三方模块支持

一些常见的第三方模块默认支持。最著名的是 silverstripe-elemental,它默认安装了几个特定的快照创建器,包括

  • 存档元素
  • 保存单个元素
  • 创建元素(GraphQL查询)
  • 编辑单个元素
  • 通过页面保存保存所有元素
  • 排序元素
  • ModelAdmin 和 GridField CSV 导入

如上所述,元素默认在其页面上也接收 snapshot_relation_tracking

另一个默认支持的模块是 GridFieldExtensions。为它的 GridFieldOrderableRows 组件提供了一个处理程序。

本地化

此模块可以配置为与 Fluent 模块一起工作。遵循 Fluent 版本历史的范式,我们不允许在版本历史中继承任何内容。我们的 SnapshotSnpashotItem 模型代表更详细的版本历史,因此我们需要应用以下配置来符合 Fluent 范式

SilverStripe\Snapshots\Snapshot:
    cms_localisation_required: 'exact'
    frontend_publish_required: 'exact'
    extensions:
        - TractorCow\Fluent\Extension\FluentExtension
    translate:
        - OriginHash

SilverStripe\Snapshots\SnapshotItem:
    cms_localisation_required: 'exact'
    frontend_publish_required: 'exact'
    extensions:
        - TractorCow\Fluent\Extension\FluentExtension
    translate:
        - ObjectHash

升级到 1.x.x

1.x.x 版本包含一些破坏性变更。我们为两者都提供了升级路径。

对象版本 DB 字段重命名

SnapshotItem 上的 DB 字段 Version 已重命名为 ObjectVersion,以防止命名冲突。请按照以下步骤进行升级。

  • 运行 composer update 以升级到此模块的所需 1.x.x 版本
  • 运行 dev/build flush=all
  • 运行 dev/tasks/migrate-object-version-task,通过 CLI 运行

遗留 Fluent 设置

这对于使用 Fluent 模块 并使用本地化快照模型的项目相关。

  • 运行 composer update 以升级到此模块的所需 1.x.x 版本
  • 根据此说明书的 本地化 部分审查和更新您的 Fluent 配置
  • 运行 dev/build flush=all
  • 运行 dev/tasks/migrate-fluent-object-hash-task,通过 CLI 运行

重新计算哈希值

对象哈希值可能已过时。建议更新它们,否则预更新历史记录项可能不会在历史查看器中显示。运行 dev/tasks/recalculate-hashes-task,通过 CLI 运行

此开发任务默认支持 Fluent

语义版本控制

此库遵循 Semver。根据 Semver,您将能够升级到此库的任何次要或补丁版本,而无需对公共 API 进行任何破坏性更改。Semver 还要求我们明确定义此库的公共 API。

所有具有public可见性的方法都属于公共API。其他所有方法不属于公共API。在可能的情况下,我们会尽量在次要版本/修补程序版本中保持protected方法的向后兼容性,但如果你正在重写方法,请在升级之前测试你的工作。

报告问题

创建一个问题,用于报告你发现的任何错误或缺少的功能。

许可证

本模块在BSD 3-Clause License下发布。