软删除嵌套子项:关于Model_Announcement与评论模型关联的技术咨询
Great question! Combining nested set behavior with soft delete requires a few targeted adjustments to your models and database, since your Model_Announcement_Comment inherits from Model_Nestedset (for tree structure) but needs the soft delete functionality normally provided by Model_Soft. Here's a step-by-step solution tailored to your setup:
1. Add the Soft Delete Column to Your Comments Table
First, you need a deleted_at timestamp column in your announcement_comments table to track when a comment is soft deleted. Create a migration to add this column:
class Migration_Add_deleted_at_to_announcement_comments extends \Fuel\Core\Migration { public function up() { \DBUtil::add_fields('announcement_comments', array( 'deleted_at' => array('type' => 'timestamp', 'null' => true), )); } public function down() { \DBUtil::drop_fields('announcement_comments', array('deleted_at')); } }
Run the migration to apply the change to your database.
2. Modify Model_Announcement_Comment to Include Soft Delete Logic
Since you can't inherit from both Model_Nestedset and Model_Soft directly, we'll add soft delete functionality manually to your comment model. This includes default scopes to exclude deleted items, overriding the delete method to soft delete instead of hard delete, and optional restore functionality.
class Model_Announcement_Comment extends Model_Nestedset { // Enable soft delete functionality protected static $_soft_delete = true; protected static $_belongs_to = array( 'announcement' => array( 'key_from' => 'announcement_id', 'model_to' => 'Model_Announcement', 'key_to' => 'id', ), ); // Define scopes to handle deleted items protected static $_scopes = array( // Default scope: exclude deleted comments 'not_deleted' => array( 'where' => array( array('deleted_at', '=', null), ), ), // Scope to include deleted comments when needed 'with_deleted' => array( 'scope' => function($query) { $query->where_open() ->where('deleted_at', '=', null) ->or_where('deleted_at', 'is not', null) ->where_close(); }, ), ); // Apply the default not_deleted scope on model initialization public static function _init() { static::add_scope('not_deleted'); } // Override delete method to perform soft delete public function delete($cascade = null) { if (static::$_soft_delete === true) { // Set the deleted_at timestamp $this->deleted_at = \Date::time()->format('mysql'); $this->save($cascade); // Optional: Cascade soft delete to all child comments $children = $this->children()->get(); foreach ($children as $child) { $child->delete($cascade); } return true; } else { // Fallback to hard delete if soft delete is disabled return parent::delete($cascade); } } // Optional: Method to restore a soft deleted comment (and its children) public function restore() { if ($this->deleted_at !== null) { $this->deleted_at = null; $this->save(); // Restore child comments too $children = $this->children()->with_deleted()->get(); foreach ($children as $child) { $child->restore(); } return true; } return false; } }
3. Adjust Model_Announcement for Cascade Soft Delete
Your announcement model has cascade_delete set to true, which by default would trigger a hard delete on comments. To make this cascade soft delete instead, override the delete method in Model_Announcement:
class Model_Announcement extends Model_Soft { protected static $_has_many = array( 'comments' => array( 'key_from' => 'id', 'model_to' => 'Model_Announcement_Comment', 'key_to' => 'announcement_id', 'cascade_save' => true, 'cascade_delete' => false, // Disable default hard delete cascade ), ); public function delete($cascade = null) { if (static::$_soft_delete === true) { // Soft delete all associated comments first foreach ($this->comments as $comment) { $comment->delete(); } // Then soft delete the announcement itself $this->deleted_at = \Date::time()->format('mysql'); return $this->save(); } else { return parent::delete($cascade); } } }
Key Notes
- Default Behavior: By default, all queries for comments will exclude soft deleted items (thanks to the
not_deletedscope). To include deleted comments, useModel_Announcement_Comment::with_deleted()->find(). - Nested Set Integrity: Soft deleted comments remain in the database with their
lft/rgtvalues intact, but they're ignored by default queries. This keeps your nested tree structure valid for active comments. - Cascade Control: The optional child cascade in the comment delete method ensures that deleting a parent comment soft deletes all its replies. You can remove this if you want to keep child comments active even when their parent is deleted.
内容的提问来源于stack exchange,提问作者Xaris Rg

