I have a CodeIgniter 4 Model.
When I return data from it with find()/findAll(), it returns all the attributes that are present in the model.
$userModel->findAll();
I'd like to hide some of them, for example, I don't want to return the dates (created_at, updated_at).
I tried to create an Entity object and return it, but it also returns everything.
Basically what I'd like to do is to have functionality like in Laravel, where you have a $hidden protected array in the Model.
I've been experimenting with the afterFind
callback, but I don't like the solution. Mainly because there is a difference in the $data array when you use find()
vs findAll()
protected $afterFind = ['prepareOutput'];
protected function prepareOutput(array $data) {
return $data;
}
$data['data']
is the actual data when using find()
$data['data']
is an array of arrays when using findAll();
Which kinda makes sense, but then I have to be sure to modify the data according to the method used.
Is there something I am missing in the documentation? Can this be done in a simpler way?
So I came up with this, but I'm still open to better and nicer solutions.
First I created my own Model and added the logic to hide some attributes:
<?php
namespace App\Models;
use CodeIgniter\Model;
class MyBaseModel extends Model {
protected $hidden = [];
public function prepareOutput(array $data) {
// if the hidden array is empty, we just return the original dta
if (sizeof($this->hidden) == 0) return $data;
// if no data was found we return the original data to ensure the right structure
if (!$data['data']) return $data;
$resultData = [];
// We want the found data to be an array, so we can loop through it.
// find() and first() return only one data item, not an array
if (($data['method'] == 'find') || ($data['method'] == 'first')) {
$data['data'] = [$data['data']];
}
if ($data['data']) {
foreach ($data['data'] as $dataItem) {
foreach ($this->hidden as $attributeToHide) {
// here we hide the unwanted attributes, but we need to check if the return type of the model is an array or an object/entity
if (is_array($dataItem)) {
unset($dataItem[$attributeToHide]);
} else {
unset($dataItem->{$attributeToHide});
}
}
array_push($resultData, $dataItem);
}
}
// return the right data structure depending on the method used
if (($data['method'] == 'find') || ($data['method'] == 'first')) {
return ['data' => $resultData[0]];
} else {
return ['data' => $resultData];
}
}
}
Now I can extend my existing models and fill in which attributes I want to hide:
<?php namespace App\Models;
use App\Entities\User;
class UserModel extends MyBaseModel {
protected $table = 'users';
protected $primaryKey = 'id';
protected $returnType = User::class;
protected $useSoftDeletes = false;
protected $allowedFields = ['email', 'password', 'first_name', 'last_name'];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
protected $allowCallbacks = true;
protected $afterFind = ['prepareOutput'];
protected $hidden = ['created_at', 'updated_at'];
}