2

I'm using an Encryptable trait to encrypt my data for the a Room model.

RoomController (/rooms) returns the decrypted data but ApiRoomController (/api/rooms) does not. How could I make it returns the decrypted data?

Encryptable Trait

trait Encryptable
{
    public function getAttribute($key)
    {
        $value = parent::getAttribute($key);
        if (in_array($key, $this->encryptable) && $value !== '' && $value !== null ) {
            $value = Crypt::decrypt($value);
        }

        return $value;
    }

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

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

RoomController index function

public function index()
{
    $rooms = Room::select('id', 'name')->get()->sortBy('name')->values()->all();

    return view('rooms.index')->withRooms($rooms);
}

ApiRoomController index function

public function index()
{
    $rooms = Room::select('id', 'name')->get()->sortBy('name')->values()->all();

    return response()->json($rooms);
}
emotality
  • 12,795
  • 4
  • 39
  • 60
Lucien Dubois
  • 1,590
  • 5
  • 28
  • 53
  • 1
    Off topic but `$value !== '' && $value !== null` can be replaced with `!empty($value)` :) Also using this trait, would like to know the answer! +1 – emotality May 09 '19 at 19:45

2 Answers2

4

I found a way using API Resources:

php artisan make:resource Rooms --collection

Then in your app/Http/Resources/Rooms.php file:

public function toArray($request)
{
    return [
        'id'   => $this->id,
        'name' => $this->name,
        // more fields here
    ];
}

Then in your ApiRoomController.php file:

use App\Http\Resources\Rooms;


public function index()
{
    $rooms = Room::select('id', 'name')->get()->sortBy('name')->values()->all();

    return Rooms::collection($rooms);
}
emotality
  • 12,795
  • 4
  • 39
  • 60
2

Seems like @emotality came up with a good solution for this already...

However, the reason for this not working as you expected is because the underlying Model's toArray() / toJson() methods do not call the getAttribute() method in your trait.

This is important because the response()->json() method maps the given collection and calls the toJson() method on each model in order to prepare it for a response.

Therefore, you can also solve this by overwriting the toArray method in your model.

class Room extends Model
{
    use Encryptable;

    public function toArray()
    {
        return [
            'id'   => $this->id,
            'name' => $this->name,
            // ...
        ];
    }
}

Jack
  • 737
  • 5
  • 10