I have an Eloquent Model, for which I created a custom toArray()
-method, to include fields from a meta table (which I get by using the eloquent-meta plugin):
class User extends Model{
// ... Other stuff
public function toArray(){
return array_merge(parent::toArray(), $this->getAllMeta()->toArray());
}
}
When I now try to send this model as a JSON response using Response::json(...)
, I get:
UnexpectedValueException in Response.php line 403: The Response content must be a string or object implementing __toString(), "boolean" given.
I have traced the error to the JsonResponse.setData($data)
-method, in which the json_encode
-call returns false. The json_last_error()
-method returns JSON_ERROR_SYNTAX
and the json_last_error_msg()
-method returns Syntax error
.
Using the debugger I stopped on the line below and evaluated the statement myself. As expected, it does not work, however if I call it like this, it works:
json_encode($data, JSON_PARTIAL_OUTPUT_ON_ERROR);
This returns the complete, valid JSON that I expect, without any missing or NULL values.
What's even stranger is, if I stop in the toArray()
-method and supply the merged array to json_encode
, it works fine, even without partial.
Am I overlooking something obvious here??
1 Answer 1
The problem was with the eloquent-meta plugin I used. Here's the relevant part from my issue:
I traced the error back to the
Helpers.maybeDecode($value)
-method:The current implementation tries to parse the value with
json_decode($value)
and checks, whether that worked, by checking thejson_last_error()
-function. The problem is, that this doesn't reset the last error.When the
Helpers.maybeDecode($value)
-method is called, while Laravel is encoding the model, and the value it tried to decode was not an valid json (for example, a simple string), the error code is set, causing thejson_encode()
-function to see it and returnnull
. The problem is with the global nature of the error-variable.My proposed workaround for this is to reset the
json_last_error()
-function after checking if decoing worked, and the only way I have found to do this is by decoding something valid (even if it's just an empty array).
Here is the Pull Request with the fix.
json_encode($mymodel->toArray())
?toArray()
-method.