I have a Model setup as so:
It is not a good idea to name a relationship the same name as one of the fields on the table. This causes issues (as you've found out) when trying to access the relationship versus accessing the field.
Ideally, your mime
field should be renamed to mime_id
. This conforms to Laravel's conventions, and is a more accurate name for the field.
However, if you don't have the ability to change the name of the field, you should change the name of the relationship.
class Upload extends Model {
protected $hidden = array('id', 'user', 'created_at', 'updated_at');
public function uploadMime() {
return $this->belongsTo('App\Models\Mime', 'mime');
}
}
In the class above, the relationship name is now uploadMime
. Additionally, the relationship was changed from a hasOne
to a belongsTo
. Since your uploads table has the foreign key to the mimes table, the Upload model belongsTo the Mime model (and the Mime model hasOne/hasMany Upload models).
Now, your code should look something like:
$data = \App\Models\Upload::with('uploadMime')->findOrFail(1);
return new JsonResponse($data);
This should give you output something along the lines of:
{
"serverPath": "upload/2015/06/06/21/filename.jpg",
"filename": "filename.jpg",
"mime": "92",
"uploadMime": {
"id": 92,
"type": "image/jpeg"
}
}
Modifying JSON using $appends
and attribute accessors
If you wanted to get closer to the JSON output you've provided in your question, you can create a mimeType
accessor and add it to the $appends
property:
class Upload extends Model {
// hide the mime field and uploadMime data
protected $hidden = array('id', 'user', 'created_at', 'updated_at', 'mime', 'uploadMime');
// add the mimeType attribute to the array
protected $appends = array('mimeType');
// code for $this->mimeType attribute
public function getMimeTypeAttribute($value) {
$mimeType = null;
if ($this->uploadMime) {
$mimeType = $this->uploadMime->type;
}
return $mimeType;
}
public function uploadMime() {
return $this->belongsTo('App\Models\Mime', 'mime');
}
}
This should give you output something along the lines of:
{
"serverPath": "upload/2015/06/06/21/filename.jpg",
"filename": "filename.jpg",
"mimeType": "image/jpeg"
}
Modifying JSON by overriding the toArray()
function
Or, if you really want the JSON to use the mime
key, you can modify the toArray()
method directly:
class Upload extends Model {
// hide uploadMime data, but not the mime field
protected $hidden = array('id', 'user', 'created_at', 'updated_at', 'uploadMime');
public function uploadMime() {
return $this->belongsTo('App\Models\Mime', 'mime');
}
// override the toArray function (called by toJson)
public function toArray() {
// get the original array to be displayed
$data = parent::toArray();
// change the value of the 'mime' key
if ($this->uploadMime) {
$data['mime'] = $this->uploadMime->type;
} else {
$data['mime'] = null;
}
return $data;
}
}
This should give you output something along the lines of:
{
"serverPath": "upload/2015/06/06/21/filename.jpg",
"filename": "filename.jpg",
"mime": "image/jpeg"
}