”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > Extending OctoberCMS:打造软删除插件教程

Extending OctoberCMS:打造软删除插件教程

发布于2025-03-12
浏览:501

Extending OctoberCMS - Building a Soft-Delete Plugin

OctoberCMS:插件扩展性深度探索及软删除插件实战

开发者通常青睐易用且可扩展的CMS。OctoberCMS 秉持简洁至上的理念,为开发者和用户带来愉悦的体验。本文将演示OctoberCMS 的一些可扩展特性,并通过一个简单的插件扩展另一个插件的功能。

Extending OctoberCMS - Building a Soft-Delete Plugin

关键要点

  • OctoberCMS 提供了一个简洁易用的CMS,同时允许通过插件进行扩展。这种扩展性体现在开发者可以深入CMS内部机制的程度,包括修改其他开发者插件的功能。
  • Rainlab Blog 插件允许创建文章并将其分配到不同的类别。本教程演示如何扩展此插件,添加软删除功能,防止文章被永久删除,而是标记为“已删除”并记录时间戳。
  • 要创建软删除功能,需要创建一个新插件,并在数据库中添加一个 deleted_at 字段。此字段将保存文章删除的时间戳。然后,插件扩展文章列表以包含此新字段作为列,并添加一个过滤器来显示或隐藏已删除的文章。
  • 创建软删除功能的最后一步是拦截文章的删除操作,并更新 deleted_at 列。这是通过挂接到 Eloquent 触发的 deleting 事件来实现的,阻止记录的删除。取而代之的是,deleted_at 字段将更新为当前时间戳,并保存记录。

引言

每个CMS都有一个插件系统来扩展平台的功能,我们通过可以深入CMS内部机制的程度来衡量其扩展性。然而,我们这里讨论的不仅仅是CMS本身,也包括插件!

如果您构建一个插件,您需要确保其他开发者可以修改您的部分功能。例如,我们有一个博客插件,用户可以通过选择列表中的文章来发布文章。最好触发一个事件来表明已发布新文章,另一个开发者可以挂接到此事件,并通过电子邮件通知订阅的用户!

class Posts extends Controller
{
    public function index_onPublish()
    {
        if (($checkedIds = post('checked')) && is_array($checkedIds) && count($checkedIds)) {

            foreach ($checkedIds as $postId) {
                if ((!$post = Post::find($postId)) || !$post->canEdit($this->user))
                    continue;

                $post->publish();
                Event::fire('rainlab.blog.posts.published', [$post]);
            }

            Flash::success('Successfully published those posts.');
        }

        return $this->listRefresh();
    }
}

其他开发者可以监听此事件来处理已发布的文章。

Event::listen('rainlab.blog.posts.published', function($post) {
    User::subscribedTo($post)->each(function($user) use($post) {
        Mail::send('emails.notifications.post-published', ['user' => $user, 'post' => $post], function($message) use($user, $post) {
            $message->from('[email protected]', 'New post by ' . $user->name);

            $message->to($user->email);
        });
    });
});

我们将主要使用事件来挂接到请求周期的不同部分。让我们从一个具体的例子开始,以便更好地理解。

Rainlab Blog 插件

如果您使用过OctoberCMS一段时间,您一定知道Rainlab Blog插件。它允许您在后端添加文章并将其附加到类别,并且您可以使用组件在前端显示它们。

在文章列表页面,我们可以删除文章。但是,如果我们想软删除它们呢?让我们看看我们能否做到这一点,并了解更多关于OctoberCMS扩展性的知识。

创建新插件

使用脚手架助手命令创建一个新的插件用于我们的演示,并在Plugin.php文件中更新插件详细信息。

php artisan create:plugin rafie.blogplus

扩展数据库模式

谈到软删除时,首先想到的是数据库中需要存在的 deleted_at 字段列。

blogplus/updates 文件夹下创建一个名为 create_posts_deleted_at_field.php 的新文件,并更新 version.yaml 文件。

# updates/version.yaml

1.0.1:
    - First version of blogplus.
    - create_posts_deleted_at_field.php
# updates/create_posts_deleted_at_field.php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostsDeletedAtField extends Migration
{
    public function up()
    {
        Schema::table('rainlab_blog_posts', function (Blueprint $table) {
            $table->timestamp('deleted_at')->nullable()->default(null);
        });
    }

    public function down()
    {
        Schema::table('rainlab_blog_posts', function (Blueprint $table) {
            $table->dropColumn('deleted_at');
        });
    }
}

迁移类将更改 rainlab_blog_posts 表并添加我们的 deleted_at 列,其默认值为 null。不要忘记运行 php artisan plugin:refresh rafie.blogplus 命令才能使更改生效。

扩展文章列表

接下来,我们必须将我们的字段作为列添加到列表中以进行显示。OctoberCMS 为我们提供了一个事件来挂接,并更改当前显示的小部件(后端列表被认为是小部件)。

// plugin.php  在Plugin类的boot方法中

Event::listen('backend.list.extendColumns', function ($widget) {
    if (!($widget->getController() instanceof \Rainlab\Blog\Controllers\Posts)) {
        return;
    }

    $widget->addColumns([
        'deleted_at' => [
            'label' => 'Deleted',
            'type' => 'date',
        ],
    ]);
});

注意:以上代码应放在 Plugin@boot 方法中。

我们有一个 if 语句来防止我们的代码在每个页面上执行,然后我们将一个新列添加到列表小部件中,我们还可以使用 removeColumn 方法删除任何现有的列。查看文档以了解可用的列选项列表。

Extending OctoberCMS - Building a Soft-Delete Plugin

扩展过滤器

文章列表顶部的栏允许用户使用日期、类别等过滤列表。在我们的例子中,我们需要一个过滤器来显示/隐藏已删除的文章。

// plugin.php  在Plugin类的boot方法中

Event::listen('backend.filter.extendScopes', function ($widget) {
    if (!($widget->getController() instanceof \Rainlab\Blog\Controllers\Posts)) {
        return;
    }

    $widget->addScopes([
        'Trashed' => [
            'label' => 'Hide trashed',
            'type' => 'checkbox',
            'scope' => 'trashed',
        ],
    ]);
});

您可以在文档中阅读更多关于列表过滤器的信息。上面的代码相当简单,只包含几个选项。但是,scope 属性应该是 Models\\Post 模型实例中定义的查询范围方法的名称。

可扩展类

October\Rain\Extension\ExtendableTrait trait 提供了一种神奇的方法来动态扩展现有类,方法是添加新的方法、属性、行为等。在我们的示例中,我们需要向文章模型添加一个新方法来处理我们的范围过滤器。

// plugin.php  在Plugin类的boot方法中

\Rainlab\Blog\Models\Post::extend(function ($model) {
    $model->addDynamicMethod('scopeTrashed', function ($query) {
        return $query->whereNull('deleted_at');
    });
});

我们可以对 addDynamicPropertyasExtension 等做同样的事情。让我们刷新我们的文章列表,看看我们的更改是否有效。

Extending OctoberCMS - Building a Soft-Delete Plugin Extending OctoberCMS - Building a Soft-Delete Plugin

当然,我们还没有任何已删除的文章,因为我们需要完成最后一部分:拦截文章的删除操作,只更新 deleted_at 列。

提示:与其使用 scope 属性,您可以使用条件来指定一个简单的 where 条件。下面的代码与使用模型范围的效果相同。

$widget->addScopes([
    'Trashed' => [
        'label' => 'Hide trashed',
        'type' => 'checkbox',
        'conditions' => 'deleted_at IS NULL',
    ],
]);

Eloquent 事件

Eloquent 在每个操作(创建、更新、删除等)上都会触发一系列事件。在这种情况下,我们需要挂接到删除事件并阻止记录的删除。

删除记录时,在执行实际删除操作之前会触发 deleting 事件,之后会触发 deleted 事件。如果您在 deleting 事件中返回 false,则操作将中止。

// plugin.php  在Plugin类的boot方法中

use Carbon\Carbon;

Event::listen('eloquent.deleting: RainLab\Blog\Models\Post', function ($record) {
    $record->deleted_at = Carbon::now();
    $record->save();
    return false;
});

现在我们准备测试最终结果!继续删除一些记录,然后转到文章列表页面,看看是否可以切换列表中的已删除项目。

结论

本文快速概述了如何扩展 OctoberCMS 平台的不同部分。您可以在文档的扩展插件部分阅读更多相关信息。如果您有任何问题或意见,请在下方留言!

关于扩展 OctoberCMS 和构建软删除插件的常见问题

OctoberCMS 中软删除插件的用途是什么?

OctoberCMS 中的软删除插件旨在防止永久性数据丢失。当您删除记录时,它不会从数据库中完全删除。相反,会为该记录设置一个 deleted_at 时间戳。这意味着从应用程序的角度来看,该记录被认为是“已删除”的,但如果需要,仍然可以检索到它。这在可能意外删除数据的场景中特别有用,因为它允许轻松恢复。

软删除功能与硬删除有何不同?

硬删除会永久地从数据库中删除记录,除非您有备份,否则无法恢复。另一方面,软删除只是将记录标记为已删除,而不会实际将其从数据库中删除。这允许您在需要时恢复记录。

如何在 OctoberCMS 中实现软删除功能?

要在 OctoberCMS 中实现软删除功能,您需要创建一个插件。这包括创建一个新插件,向数据库表添加 deleted_at 列,并更新您的模型以使用 SoftDeletes trait。然后,您可以使用模型上的 delete 方法来软删除记录,并使用 restore 方法来恢复它。

如何测试 OctoberCMS 中的软删除功能?

您可以通过创建单元测试来测试软删除功能。这包括创建一个新的测试用例,在数据库中创建一个新记录,软删除它,然后断言它仍然存在于数据库中,但被标记为已删除。

我可以将软删除功能与现有记录一起使用吗?

是的,您可以将软删除功能与现有记录一起使用。您只需要向现有的数据库表添加 deleted_at 列。所有现有记录的此列都将具有 null 值,表示它们尚未被删除。

如何在 OctoberCMS 中恢复软删除的记录?

要恢复软删除的记录,您可以使用模型上的 restore 方法。这将从记录中删除 deleted_at 时间戳,有效地“取消删除”它。

我可以在 OctoberCMS 中永久删除软删除的记录吗?

是的,您可以使用模型上的 forceDelete 方法永久删除软删除的记录。这将像硬删除一样从数据库中删除记录。

如何在 OctoberCMS 中查看所有记录,包括软删除的记录?

要查看所有记录,包括软删除的记录,您可以使用模型上的 withTrashed 方法。这将返回所有记录,无论它们是否已被软删除。

我可以在 OctoberCMS 中自定义 deleted_at 列的名称吗?

是的,您可以通过覆盖模型中的 getDeletedAtColumn 方法来自定义 deleted_at 列的名称。如果 deleted_at 不适合您的需求,这允许您使用不同的列名。

我可以在 OctoberCMS 中为某些记录禁用软删除功能吗?

是的,您可以使用模型上的 withoutGlobalScope 方法为某些记录禁用软删除功能。这允许您从软删除功能中排除某些记录。

最新教程 更多>
  • 如何在php中使用卷发发送原始帖子请求?
    如何在php中使用卷发发送原始帖子请求?
    如何使用php 创建请求来发送原始帖子请求,开始使用curl_init()开始初始化curl session。然后,配置以下选项: curlopt_url:请求 [要发送的原始数据指定内容类型,为原始的帖子请求指定身体的内容类型很重要。在这种情况下,它是文本/平原。要执行此操作,请使用包含以下标头...
    编程 发布于2025-05-18
  • 如何在无序集合中为元组实现通用哈希功能?
    如何在无序集合中为元组实现通用哈希功能?
    在未订购的集合中的元素要纠正此问题,一种方法是手动为特定元组类型定义哈希函数,例如: template template template 。 struct std :: hash { size_t operator()(std :: tuple const&tuple)const {...
    编程 发布于2025-05-18
  • 找到最大计数时,如何解决mySQL中的“组函数\”错误的“无效使用”?
    找到最大计数时,如何解决mySQL中的“组函数\”错误的“无效使用”?
    如何在mySQL中使用mySql 检索最大计数,您可能会遇到一个问题,您可能会在尝试使用以下命令:理解错误正确找到由名称列分组的值的最大计数,请使用以下修改后的查询: 计数(*)为c 来自EMP1 按名称组 c desc订购 限制1 查询说明 select语句提取名称列和每个名称...
    编程 发布于2025-05-18
  • Java开发者如何保护数据库凭证免受反编译?
    Java开发者如何保护数据库凭证免受反编译?
    在java 在单独的配置文件保护数据库凭证的最有效方法中存储凭据是将它们存储在单独的配置文件中。该文件可以在运行时加载,从而使登录数据从编译的二进制文件中远离。使用prevereness class import java.util.prefs.preferences; 公共类示例{ 首选项...
    编程 发布于2025-05-18
  • 反射动态实现Go接口用于RPC方法探索
    反射动态实现Go接口用于RPC方法探索
    在GO 使用反射来实现定义RPC式方法的界面。例如,考虑一个接口,例如:键入myService接口{ 登录(用户名,密码字符串)(sessionId int,错误错误) helloworld(sessionid int)(hi String,错误错误) } 替代方案而不是依靠反射...
    编程 发布于2025-05-18
  • 版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    在时间戳列上使用current_timestamp或MySQL版本中的current_timestamp或在5.6.5 此限制源于遗留实现的关注,这些限制需要对当前的_timestamp功能进行特定的实现。 创建表`foo`( `Productid` int(10)unsigned not n...
    编程 发布于2025-05-18
  • 为什么在我的Linux服务器上安装Archive_Zip后,我找不到“ class \” class \'ziparchive \'错误?
    为什么在我的Linux服务器上安装Archive_Zip后,我找不到“ class \” class \'ziparchive \'错误?
    Class 'ZipArchive' Not Found Error While Installing Archive_Zip on Linux ServerSymptom:When attempting to run a script that utilizes the ZipAr...
    编程 发布于2025-05-18
  • 为什么PHP的DateTime :: Modify('+1个月')会产生意外的结果?
    为什么PHP的DateTime :: Modify('+1个月')会产生意外的结果?
    使用php dateTime修改月份:发现预期的行为在使用PHP的DateTime类时,添加或减去几个月可能并不总是会产生预期的结果。正如文档所警告的那样,“当心”这些操作的“不像看起来那样直观。 考虑文档中给出的示例:这是内部发生的事情: 现在在3月3日添加另一个月,因为2月在2001年只有2...
    编程 发布于2025-05-18
  • 在GO中构造SQL查询时,如何安全地加入文本和值?
    在GO中构造SQL查询时,如何安全地加入文本和值?
    在go中构造文本sql查询时,在go sql queries 中,在使用conting and contement和contement consem per时,尤其是在使用integer per当per当per时,per per per当per. [&​​&&&&&&&&&&&&&&&默元组方法在...
    编程 发布于2025-05-18
  • Java为何无法创建泛型数组?
    Java为何无法创建泛型数组?
    通用阵列创建错误 arrayList [2]; JAVA报告了“通用数组创建”错误。为什么不允许这样做?答案:Create an Auxiliary Class:public static ArrayList<myObject>[] a = new ArrayList<myO...
    编程 发布于2025-05-18
  • Python不会对超范围子串切片报错的原因
    Python不会对超范围子串切片报错的原因
    在python中用索引切片范围:二重性和空序列索引单个元素不同,该元素会引起错误,切片在序列的边界之外没有。这种行为源于索引和切片之间的基本差异。索引一个序列,例如“示例” [3],返回一个项目。但是,切片序列(例如“示例” [3:4])返回项目的子序列。索引不存在的元素时,例如“示例” [9] ...
    编程 发布于2025-05-18
  • 表单刷新后如何防止重复提交?
    表单刷新后如何防止重复提交?
    在Web开发中预防重复提交 在表格提交后刷新页面时,遇到重复提交的问题是常见的。要解决这个问题,请考虑以下方法: 想象一下具有这样的代码段,看起来像这样的代码段:)){ //数据库操作... 回声“操作完成”; 死(); } ?> ...
    编程 发布于2025-05-18
  • `console.log`显示修改后对象值异常的原因
    `console.log`显示修改后对象值异常的原因
    foo = [{id:1},{id:2},{id:3},{id:4},{id:id:5},],]; console.log('foo1',foo,foo.length); foo.splice(2,1); console.log('foo2', foo, foo....
    编程 发布于2025-05-18
  • 同实例无需转储复制MySQL数据库方法
    同实例无需转储复制MySQL数据库方法
    在同一实例上复制一个MySQL数据库而无需转储在同一mySQL实例上复制数据库,而无需创建InterMediate sqql script。以下方法为传统的转储和IMPORT过程提供了更简单的替代方法。 直接管道数据 MySQL手动概述了一种允许将mysqldump直接输出到MySQL clie...
    编程 发布于2025-05-18

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3