」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > Extending OctoberCMS:打造軟刪除插件教程

Extending OctoberCMS:打造軟刪除插件教程

發佈於2025-03-12
瀏覽:447

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 ;?>" method="post">The intention is to capture the input from the text box and display it when the submit button is clicked.但是,輸出...
    程式設計 發佈於2025-05-18
  • CSS強類型語言解析
    CSS強類型語言解析
    您可以通过其强度或弱输入的方式对编程语言进行分类的方式之一。在这里,“键入”意味着是否在编译时已知变量。一个例子是一个场景,将整数(1)添加到包含整数(“ 1”)的字符串: result = 1 "1";包含整数的字符串可能是由带有许多运动部件的复杂逻辑套件无意间生成的。它也可以是故意从单个真理...
    程式設計 發佈於2025-05-18
  • HTML格式標籤
    HTML格式標籤
    HTML 格式化元素 **HTML Formatting is a process of formatting text for better look and feel. HTML provides us ability to format text without us...
    程式設計 發佈於2025-05-18
  • Python不會對超範圍子串切片報錯的原因
    Python不會對超範圍子串切片報錯的原因
    在python中用索引切片範圍:二重性和空序列索引單個元素不同,該元素會引起錯誤,切片在序列的邊界之外沒有。 這種行為源於索引和切片之間的基本差異。索引一個序列,例如“示例” [3],返回一個項目。但是,切片序列(例如“示例” [3:4])返回項目的子序列。 索引不存在的元素時,例如“示例” [9...
    程式設計 發佈於2025-05-18
  • Python中何時用"try"而非"if"檢測變量值?
    Python中何時用"try"而非"if"檢測變量值?
    使用“ try“ vs.” if”來測試python 在python中的變量值,在某些情況下,您可能需要在處理之前檢查變量是否具有值。在使用“如果”或“ try”構建體之間決定。 “ if” constructs result = function() 如果結果: 對於結果: ...
    程式設計 發佈於2025-05-18
  • 如何從Python中的字符串中刪除表情符號:固定常見錯誤的初學者指南?
    如何從Python中的字符串中刪除表情符號:固定常見錯誤的初學者指南?
    從python import codecs import codecs import codecs 導入 text = codecs.decode('這狗\ u0001f602'.encode('utf-8'),'utf-8') 印刷(文字)#帶有...
    程式設計 發佈於2025-05-18
  • 在C#中如何高效重複字符串字符用於縮進?
    在C#中如何高效重複字符串字符用於縮進?
    在基於項目的深度下固定字符串時,重複一個字符串以進行凹痕,很方便有效地有一種有效的方法來返回字符串重複指定的次數的字符串。使用指定的次數。 constructor 這將返回字符串“ -----”。 字符串凹痕= new String(' - ',depth); console.W...
    程式設計 發佈於2025-05-18
  • 找到最大計數時,如何解決mySQL中的“組函數\”錯誤的“無效使用”?
    找到最大計數時,如何解決mySQL中的“組函數\”錯誤的“無效使用”?
    如何在mySQL中使用mySql 檢索最大計數,您可能會遇到一個問題,您可能會在嘗試使用以下命令:理解錯誤正確找到由名稱列分組的值的最大計數,請使用以下修改後的查詢: 計數(*)為c 來自EMP1 按名稱組 c desc訂購 限制1 查詢說明 select語句提取名稱列和每個名稱...
    程式設計 發佈於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中的數組中提取隨機元素?
    如何從PHP中的數組中提取隨機元素?
    從陣列中的隨機選擇,可以輕鬆從數組中獲取隨機項目。考慮以下數組:; 從此數組中檢索一個隨機項目,利用array_rand( array_rand()函數從數組返回一個隨機鍵。通過將$項目數組索引使用此鍵,我們可以從數組中訪問一個隨機元素。這種方法為選擇隨機項目提供了一種直接且可靠的方法。
    程式設計 發佈於2025-05-18
  • 如何在鼠標單擊時編程選擇DIV中的所有文本?
    如何在鼠標單擊時編程選擇DIV中的所有文本?
    在鼠標上選擇div文本單擊帶有文本內容,用戶如何使用單個鼠標單擊單擊div中的整個文本?這允許用戶輕鬆拖放所選的文本或直接複製它。 在單個鼠標上單擊的div元素中選擇文本,您可以使用以下Javascript函數: function selecttext(canduterid){ if(d...
    程式設計 發佈於2025-05-18
  • MySQL中如何高效地根據兩個條件INSERT或UPDATE行?
    MySQL中如何高效地根據兩個條件INSERT或UPDATE行?
    在兩個條件下插入或更新或更新 solution:的答案在於mysql的插入中...在重複鍵更新語法上。如果不存在匹配行或更新現有行,則此功能強大的功能可以通過插入新行來進行有效的數據操作。如果違反了唯一的密鑰約束。 實現所需的行為,該表必須具有唯一的鍵定義(在這種情況下為'名稱'...
    程式設計 發佈於2025-05-18
  • 為什麼我的CSS背景圖像出現?
    為什麼我的CSS背景圖像出現?
    故障排除:CSS背景圖像未出現 ,您的背景圖像儘管遵循教程說明,但您的背景圖像仍未加載。圖像和样式表位於相同的目錄中,但背景仍然是空白的白色帆布。 而不是不棄用的,您已經使用了CSS樣式: bockent {背景:封閉圖像文件名:背景圖:url(nickcage.jpg); 如果您的html,cs...
    程式設計 發佈於2025-05-18
  • eval()vs. ast.literal_eval():對於用戶輸入,哪個Python函數更安全?
    eval()vs. ast.literal_eval():對於用戶輸入,哪個Python函數更安全?
    稱量()和ast.literal_eval()中的Python Security 在使用用戶輸入時,必須優先確保安全性。強大的Python功能Eval()通常是作為潛在解決方案而出現的,但擔心其潛在風險。本文深入研究了eval()和ast.literal_eval()之間的差異,突出顯示其安全性含義...
    程式設計 發佈於2025-05-18
  • 如何在Java中正確顯示“ DD/MM/YYYY HH:MM:SS.SS”格式的當前日期和時間?
    如何在Java中正確顯示“ DD/MM/YYYY HH:MM:SS.SS”格式的當前日期和時間?
    如何在“ dd/mm/yyyy hh:mm:mm:ss.ss”格式“ gormat 解決方案: args)拋出異常{ 日曆cal = calendar.getInstance(); SimpleDateFormat SDF =新的SimpleDateFormat(“...
    程式設計 發佈於2025-05-18

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3