解密模型值的访问器不工作

Accessor that decrypts model value isn't working

我有一个使用访问器和修改器来加密模型值的特征:

trait Encryptable
{
    public function getAttribute($key)
    {
        $value = parent::getAttribute($key);

        if (in_array($key, $this->encryptable)) {
            $value = Crypt::decrypt($value);
            return $value;
        } else {
            return $value;
        }
    }

    public function setAttribute($key, $value)
    {
        if (in_array($key, $this->encryptable)) {
            $value = Crypt::encrypt($value);
        }

        return parent::setAttribute($key, $value);
    }
} 

评论模型

protected $fillable = ['content','user_id','commentable_id', 'commentable_type'];
protected $encryptable = [
    'content'
];

评论控制器

public function storePostComment(Request $request, Post $Post)
{
    $this->validate($request, [
        'content' => 'required',
    ]);

    $comment = $post->comments()->create([
        'user_id' => auth()->user()->id,
        'content' => $request->content
    ]);
    
    
    dd($comment->content);
    //return new CommentResource($comment);
}

发生的事情是,当我通过 return new CommentResource($comment); 给我加密的评论内容时,dd($comment->content); 解密了评论内容。如何解密整个评论对象以便将其输出到资源中?

编辑评论资源

class CommentResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'content' => $this->content,
            'owner' => $this->owner,
        ];
    }
} 

编辑 2 作为答案

这是我的尝试:

use App\Comment;

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class CommentResource extends JsonResource
{
    
    public function __construct(Comment $resource)
    {
        $this->resource = $resource;
    }
    
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'content' => $this->content,
            'owner' => $this->owner,
        ];
    }
}

错误:

Argument 1 passed to App\Http\Resources\CommentResource::__construct() must be an instance of App\Http\Resources\Comment, instance of App\Comment given, called in /Applications/MAMP/htdocs/my-app/app/Http/Controllers/Api/CommentController.php on line 31

编辑 3(最终编辑)

这是我的发现:

我尝试了一系列不同的组合以及@Edwin Krause 的回答。我有另一个模型使用这个可加密的特征并在一个工作正常的资源中输出。

为了给这个问题更多的上下文,我发现在测试中使用 assertJsonFragment 有问题:

评论测试

/* @test **/
public function a_user_can_comment_on_a_post()
{
    $decryptedComment = ['content'=>'A new content']
    $response = $this->json('POST',  '/api/comment/' . $post->id, $decryptedComment);

        $response->assertStatus(201);

        $response->assertJsonStructure([
            'data' => [
                'owner',
                'content'
            ]
        ])
        ->assertJsonFragment(['content' => $decryptedContent['content']]);
}

assertJsonFragment 正在返回加密内容,因此失败,因为它正在针对解密的评论内容进行测试。

我在控制器中使用 dd(new CommentResource($comment)); 来检查内容是否正在解密,但没有。

我尝试了在控制器方法中使用 dd() 进行各种不同的故障排除,甚至在浏览器中进行了测试。依然没有。我添加了@Edwin Krause 代码,但 dd()

上仍然没有任何内容

我终于幸运地摆脱了 dd() 与@Edwin Krause 并将我的控制器更改为:

我的 CommentResource 中的工作代码与@Edwin Krause 的回答相结合

$comment = Comment::create([
    'user_id' => auth()->user()->id,
    'content' => $request->content,
    'commentable_type' => 'App\Post',
    'commentable_id' => $post->id,
]);

return new CommentResource($comment);

测试通过了。我试过 dd(new CommentResource($comment));,内容仍然是加密的。浏览器上的内容输出和 assertJsonFragment 有效。我一定尝试了很多组合来尝试解决这个问题,我有点幸运。

我不确定为什么会这样,但我已经在这上面花了好几个小时,所以我无法解决它崩溃的原因。也许其他人可以。

只是建议尝试覆盖 JsonResource 的构造函数并将 $resource 参数类型转换为您的模型类。 它适用于其他用途,不确定是否能解决您的问题,需要测试

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;
use App\Comment;

class CommentResource extends JsonResource
{

  public function __construct(Comment $resource)
  {
    $this->resource = $resource;
    $this->resource->content = $resource->content;
  }

  ....

编辑: 我对构造函数进行了更多尝试,修改后的版本应该可以正常工作。我没有任何加密数据可以玩,但从逻辑上讲这应该可以。