I have models with attributes which contains objects of classes with protected properties. I want to output the model in json including the protected properties.
I am working with these constraints:
-
class MyModel extends Model {}
class Pen {
protected $colour = 'red';
}
class Library {
public static function pineapple(Pen $pen) {
}
}
$myModel->pen = (new Pen);
// I need to use them for a third party library so I should not change the class
Library::pineapple($myModel->pen);
// In controller
return response()->json([
'data' => $myModel
]);
I want the output to contain {pen: { colour: 'red' }}
Assuming there is some method on the Pen
class to get the $colour
attribute (e.g. getColour()
), you could modify the toArray()
method on your model to build the pen
output manually.
class MyModel extends Model
{
public function toArray()
{
$array = parent::toArray();
if (!empty($this->pen)) {
$array['pen'] = ['colour' => $this->pen->getColour()];
}
return $array;
}
}
In the Model
, toArray()
is called by jsonSerialize()
, which is called by the response when it json_encode
s the data you pass into the json()
method.
I managed to solve this by extending the model and using symphony/serializer component.
Below is the base model that has to be extended by all models needing this functionality.
Note that I have encoded then decoded it in the return
line. The jsonSerialize()
method - toJson()
is the actual method that encodes it. However, modifying toJson()
directly did not work as it is skipped over when using response()->json()
in controller;
Also, I had to composer require symfony/property-access
it's a dependency of ObjectNormalizer
.
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
class ProtectedSerializableModel extends Model
{
public function jsonSerialize()
{
$serializer = (new Serializer([new ObjectNormalizer()], [new JsonEncoder()]));
$attributes = $this->toArray();
foreach($attributes as $k => &$v) {
if(is_object($v)) {
$v = get_object_vars($v);
}
}
return json_decode($serializer->serialize($attributes, 'json'));
}
}