diff --git a/src/Models/Comment.php b/src/Models/Comment.php index c04ede11..f6f9c333 100644 --- a/src/Models/Comment.php +++ b/src/Models/Comment.php @@ -119,8 +119,6 @@ public function replies() */ public static function publish(array $attributes): Comment { - static::unguard(); - // If replies or parent is set somehow unset it unset($attributes['replies'], $attributes['parent']); @@ -139,9 +137,10 @@ public static function publish(array $attributes): Comment $attributes['created_at'] = now(); $attributes['updated_at'] = now(); - $comment = static::create($attributes); - static::reguard(); - - return $comment; + // Unguard only for this insert: `unguarded()` restores the guard even when the insert + // throws. A bare unguard() left every model in a long-lived (Octane) worker unguarded + // after a failed insert, so request params became where clauses and stray payload keys + // became insert columns on unrelated models. + return static::unguarded(fn () => static::create($attributes)); } } diff --git a/tests/Unit/Models/OperationalModelsTest.php b/tests/Unit/Models/OperationalModelsTest.php index 4978d81d..af164fe8 100644 --- a/tests/Unit/Models/OperationalModelsTest.php +++ b/tests/Unit/Models/OperationalModelsTest.php @@ -636,6 +636,21 @@ public function clear(): bool Carbon::setTestNow(); }); +it('leaves models guarded when publishing a comment fails', function () { + operational_models_database(); + session([ + 'user' => 'user-1', + 'company' => 'company-1', + ]); + + // A duplicate primary key makes the insert throw. + Comment::publish(['uuid' => 'comment-dup', 'content' => 'First', 'subject_uuid' => 'order-1', 'subject_type' => User::class]); + + expect(fn () => Comment::publish(['uuid' => 'comment-dup', 'content' => 'Second', 'subject_uuid' => 'order-1', 'subject_type' => User::class])) + ->toThrow(Exception::class) + ->and(Comment::isUnguarded())->toBeFalse(); +}); + it('defines comment company parent and replies relationship contracts', function () { operational_models_database();