MediaWiki扩展中获取页面编辑前后内容的教程

心靈之曲
发布: 2025-10-09 10:16:01
原创
261人浏览过

MediaWiki扩展中获取页面编辑前后内容的教程

在MediaWiki扩展的MultiContentSave钩子中,开发者需要获取页面在保存编辑前后的内容以进行比较或处理。本文将详细指导如何利用RenderedRevision对象获取新内容,并通过getParentId()和RevisionStore服务获取前一版本内容,从而实现对页面编辑前后内容的全面访问和处理。

理解 MultiContentSave 钩子

multicontentsave 钩子是mediawiki提供的一个关键扩展点,它在页面内容被保存(无论是新建、编辑还是回退)之后触发。这个钩子为开发者提供了在内容持久化到数据库后,对页面内容进行进一步处理、分析或记录的机会。

钩子的签名如下:

public static function onMultiContentSave(
    RenderedRevision $renderedRevision,
    UserIdentity $user,
    CommentStoreComment $summary,
    $flags,
    Status $hookStatus
)
登录后复制

其中,$renderedRevision 参数是核心,它包含了当前保存的修订版本的所有信息,包括新内容。

获取编辑后的新内容

获取页面编辑后的新内容相对直接。$renderedRevision 对象封装了当前保存的修订版本 (Revision)。我们可以通过它来访问新内容。

use MediaWiki\Revision\RenderedRevision;
use MediaWiki\Revision\RevisionRecord;
use Wikimedia\Content\SlotRecord;

class MyExtensionHooks {
    public static function onMultiContentSave(
        RenderedRevision $renderedRevision,
        UserIdentity $user,
        CommentStoreComment $summary,
        $flags,
        Status $hookStatus
    ) {
        // 获取当前修订版本对象
        $revision = $renderedRevision->getRevision();

        // 获取页面的 LinkTarget 对象(包含页面标题信息,非直接字符串)
        $title = $revision->getPageAsLinkTarget();

        // 获取编辑后的新内容
        // SlotRecord::MAIN 表示主内容槽
        // RevisionRecord::RAW 表示获取原始维基文本内容
        $new_content_object = $revision->getContent(SlotRecord::MAIN, RevisionRecord::RAW);
        $new_content_text = $new_content_object ? $new_content_object->getNativeData() : '';

        // $new_content_text 现在包含了编辑后的页面内容

        return true;
    }
}
登录后复制

上述代码中,$revision-youjiankuohaophpcngetContent(SlotRecord::MAIN, RevisionRecord::RAW) 返回一个 Content 对象。通过调用 $new_content_object->getNativeData(),我们可以获取到其原始的字符串表示(通常是维基文本)。

获取编辑前的旧内容

获取编辑前的旧内容是本教程的核心挑战。MediaWiki的修订版本系统通过父子关系来跟踪历史。当前修订版本对象 ($revision) 包含了对其父版本(即编辑前的版本)的引用。

以下是获取旧内容的步骤:

  1. 获取父版本ID: 每个修订版本都有一个父版本ID,指向它所基于的上一版本。我们可以通过 $revision->getParentId() 方法获取这个ID。

    • 如果页面是首次创建,getParentId() 将返回 0,表示没有父版本。
    • 如果父版本未知或未定义,它可能返回 null。
  2. 通过ID加载前一个修订版本: 一旦我们有了父版本ID,就可以使用 MediaWiki\Revision\RevisionStore 服务来加载对应的修订版本对象。RevisionStore::getRevisionById() 方法可以根据ID检索修订版本。

    • 如果找不到对应的修订版本,此方法将返回 null。
  3. 从前一个修订版本中提取内容: 加载到前一个修订版本对象后,获取其内容的方式与获取新内容类似。

下面是获取旧内容的具体实现:

use MediaWiki\Revision\RenderedRevision;
use MediaWiki\WikiPage\Revision\RevisionStore; // 确保引入正确的 RevisionStore
use MediaWiki\Revision\RevisionRecord;
use Wikimedia\Content\SlotRecord;
use MediaWiki\Content\ContentHandler; // 用于将Content对象转换为文本

class MyExtensionHooks {
    public static function onMultiContentSave(
        RenderedRevision $renderedRevision,
        UserIdentity $user,
        CommentStoreComment $summary,
        $flags,
        Status $hookStatus
    ) {
        $revision = $renderedRevision->getRevision();
        $title = $revision->getPageAsLinkTarget(); // 获取页面的 LinkTarget 对象

        // 获取编辑后的新内容
        $new_content_object = $revision->getContent(SlotRecord::MAIN, RevisionRecord::RAW);
        $new_content_text = $new_content_object ? $new_content_object->getNativeData() : '';

        // --- 获取编辑前的旧内容 ---

        $old_content_text = ''; // 初始化旧内容为空字符串

        // 1. 获取父版本ID
        $parent_id = $revision->getParentId();

        // 2. 检查是否存在父版本(即不是首次创建)
        if ($parent_id !== 0 && $parent_id !== null) {
            // 3. 通过父版本ID加载前一个修订版本
            // RevisionStore 是一个服务,通常通过 MediaWiki\MediaWikiServices::getInstance()->getRevisionStore() 获取
            // 但在钩子环境中,可以直接访问静态方法 RevisionStore::getRevisionById()
            $previous_revision = RevisionStore::getRevisionById($parent_id);

            // 4. 检查是否成功加载到前一个修订版本
            if ($previous_revision) {
                // 5. 从前一个修订版本中提取内容
                // Revision::RAW 获取原始内容
                $old_content_object = $previous_revision->getContent(SlotRecord::MAIN, RevisionRecord::RAW);

                // 6. 将内容对象转换为文本
                // ContentHandler::getContentText() 是一个通用的转换方法
                $old_content_text = $old_content_object ? ContentHandler::getContentText($old_content_object) : '';
            }
        }

        // $old_content_text 现在包含了编辑前的页面内容

        // ... 在这里可以对 $new_content_text 和 $old_content_text 进行比较或处理

        return true;
    }
}
登录后复制

完整示例:比较编辑前后内容

将新旧内容获取逻辑整合在一起,可以方便地进行内容比较,例如实现一个简单的内容差异检测或审计功能。

豆包AI编程
豆包AI编程

豆包推出的AI编程助手

豆包AI编程 483
查看详情 豆包AI编程
<?php

// 导入必要的类
use MediaWiki\Hook\MultiContentSaveHook;
use MediaWiki\Revision\RenderedRevision;
use MediaWiki\User\UserIdentity;
use CommentStoreComment;
use Status;
use MediaWiki\WikiPage\Revision\RevisionStore;
use MediaWiki\Revision\RevisionRecord;
use Wikimedia\Content\SlotRecord;
use MediaWiki\Content\ContentHandler;

/**
 * 示例 MediaWiki 扩展钩子类
 */
class ContentComparisonExtensionHooks implements MultiContentSaveHook {

    /**
     * 在内容保存后触发,用于比较编辑前后内容。
     *
     * @param RenderedRevision $renderedRevision 当前保存的修订版本信息
     * @param UserIdentity $user 执行保存操作的用户
     * @param CommentStoreComment $summary 编辑摘要
     * @param int $flags 保存标志
     * @param Status $hookStatus 钩子状态对象
     * @return bool
     */
    public function onMultiContentSave(
        RenderedRevision $renderedRevision,
        UserIdentity $user,
        CommentStoreComment $summary,
        $flags,
        Status $hookStatus
    ): bool {
        // 获取当前修订版本对象
        $currentRevision = $renderedRevision->getRevision();
        $pageTitle = $currentRevision->getPageAsLinkTarget()->getText(); // 获取页面标题字符串

        // --- 获取编辑后的新内容 ---
        $newContentObject = $currentRevision->getContent(SlotRecord::MAIN, RevisionRecord::RAW);
        $newContentText = $newContentObject ? ContentHandler::getContentText($newContentObject) : '';

        // --- 获取编辑前的旧内容 ---
        $oldContentText = ''; // 默认旧内容为空

        $parentId = $currentRevision->getParentId();

        // 检查是否存在父版本 (即不是首次创建页面)
        if ($parentId !== 0 && $parentId !== null) {
            // 通过父版本ID加载前一个修订版本
            $previousRevision = RevisionStore::getRevisionById($parentId);

            if ($previousRevision) {
                // 从前一个修订版本中提取内容
                $oldContentObject = $previousRevision->getContent(SlotRecord::MAIN, RevisionRecord::RAW);
                $oldContentText = $oldContentObject ? ContentHandler::getContentText($oldContentObject) : '';
            } else {
                // 无法加载到前一个修订版本 (可能ID无效或已删除)
                wfDebugLog('ContentComparisonExtension', "Warning: Could not load previous revision with ID $parentId for page $pageTitle.");
            }
        } else {
            // 这是页面的首次创建,没有旧内容
            wfDebugLog('ContentComparisonExtension', "Page '$pageTitle' was created. No old content to compare.");
        }

        // --- 进行内容比较或进一步处理 ---
        if ($oldContentText !== $newContentText) {
            // 内容发生了变化
            wfDebugLog('ContentComparisonExtension', "Page '$pageTitle' content changed.");
            // 可以在此处执行差异分析、记录日志、发送通知等操作
            // 例如:
            // $diff = new \MediaWiki\Diff\TextDiffer();
            // $changes = $diff->getDiff($oldContentText, $newContentText);
            // ...
        } else {
            // 内容没有变化 (可能只是保存了空编辑或元数据编辑)
            wfDebugLog('ContentComparisonExtension', "Page '$pageTitle' content unchanged.");
        }

        return true; // 总是返回 true,除非你想阻止保存操作
    }
}
登录后复制

在 extension.json 中注册钩子:

{
    "name": "ContentComparisonExtension",
    "version": "1.0.0",
    "AutoloadClasses": {
        "ContentComparisonExtensionHooks": "ContentComparisonExtensionHooks.php"
    },
    "Hooks": {
        "MultiContentSave": [
            "ContentComparisonExtensionHooks::onMultiContentSave"
        ]
    },
    "manifest_version": 2
}
登录后复制

注意事项与最佳实践

  1. 错误处理与空值检查:

    • $revision->getParentId() 可能返回 0 或 null。在尝试加载前一个修订版本之前,务必进行检查。
    • RevisionStore::getRevisionById() 可能返回 null。在尝试访问 null 对象的属性之前,也应进行检查。
    • getContent() 方法返回的 Content 对象也可能为 null,因此在调用 getNativeData() 或 ContentHandler::getContentText() 之前进行检查。
  2. 性能考虑:

    • 频繁地加载旧版本内容可能会对大型Wiki的性能产生影响,尤其是在高流量或频繁编辑的页面上。如果只需要简单的标记或审计,可以考虑只存储哈希值进行比较,而不是加载完整内容。
  3. 内容格式:

    • RevisionRecord::RAW 用于获取原始的维基文本。如果页面内容是其他类型(例如JSON或自定义内容模型),可能需要使用不同的 SlotRecord 或 RevisionRecord 常量,并使用相应的 ContentHandler 方法进行处理。
    • SlotRecord::MAIN 用于获取页面的主要内容槽。MediaWiki 5.x 版本引入了多内容槽机制,如果你的扩展需要处理非主内容槽的内容,需要指定相应的 SlotRecord 常量。
  4. 钩子返回值:

    • MultiContentSave 钩子通常应返回 true,表示钩子已成功处理且不应阻止后续操作。如果返回 false,可能会中断MediaWiki的正常保存流程。

总结

通过本教程,我们详细学习了如何在MediaWiki扩展的MultiContentSave钩子中,有效地获取页面编辑前后的内容。关键在于利用RenderedRevision对象获取当前修订版本,并通过其getParentId()方法和RevisionStore服务来检索并访问前一个修订版本的内容。掌握这些技术,开发者可以构建出功能强大、能够深入分析和处理页面内容变化的MediaWiki扩展。在实际开发中,务必注意错误处理、性能优化以及内容格式的兼容性。

以上就是MediaWiki扩展中获取页面编辑前后内容的教程的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号