Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bentinata's avatar

BelongsTo Modify Object Instead Only Getting Data

I got 3 tables in MySQL. place, user, act. place has one-to-many relationship with user, so do user with act.

In every model, I add belongsTo that return parent record. Like:

class User extends Eloquent {
    ...
    public function place(){
        return $this->belongsTo('Place');
    }
}

But, when I create API for getting list of user with embedded place name, it also return the place object.

Ex:

$users = Users::get();

foreach($users as $key => $value){
    $value->place_name=$value->place->name;
}

return $user;

Would result:

[
    {
        "id": 1,
        "name": "Ben",
        "place_id": 1,
        "place_name": "Home",
        "place": {              // <-- unwanted place object
            "id": 1,
            "name": "Home"
        }
    }
]

Even simple $value->place call inside query would result called object added to original object.

I also tried using

$value->place_name=Users::find($value->place_id)->place->name;

But it'll result non Object error after some iteration.

Is this intended? Or do I do it wrong?

0 likes
6 replies
JarekTkaczyk's avatar

@bentinata It is expected behaviour, because of this:

$model->relation; // loads the relation and stores it in relations array

// in your case it is called here
... $value->place->name;

Now, depending on what you want to achieve, you may do it in a couple of ways:

  1. hide the place relation and use accessor
  2. use joins instead of relations
  3. map place_name attribute to related field using Mappable from this package https://github.com/jarektkaczyk/eloquence - however mind that it's under heavy development and is subject to change pretty often (today to start with)

and more.. So tell us what is your goal here exactly - a use case will be the easiest way.

bentinata's avatar

@JarekTkaczyk Eh, how to undo best answer? :P

Hmm... could you explain the first? I don't know how to hide a particular element from an object.

For the second option, I already knew that I could do it in Fluent query builder, but I was experimenting with Eloquent. I was dealing with multi-level relationship anyway, so yeah, Eloquent was easier. My API return now got 4-level-nested JSON because of this.

While I don't mind using unstable package, Laravel is something new to me (come from Node), so I'd rather not taking the risk of pulling my hair.

What I want is just showing particular fields, not all of it.

bentinata's avatar

@JarekTkaczyk Eh, don't leave me alone ok? I'm curious. I'm not forcing you to answer, but just don't forgot me. :(

JarekTkaczyk's avatar
Level 53

@bentinata I don't think you can cancel, but you can choose another answer I suppose. However why would you want that possibly? ;)

Yeah, I understand you want to show only chosen fields. I suppose it is an API call that uses Eloquent directly, ie. no transformers?

So, here's the 1st option:

// User model
protected $hidden = ['place']; // won't be shown in toArray/toJson representation

protected $appends = ['place_name']; // will be appended to toArray/toJson representation - accessor is required

// accessor for place_name dynamic property
public function getPlaceNameAttribute()
{
    $place = $this->place; // might be null, so let's check it

    return $place ? $place->name : null;
}

Here are references for you: hidden & appends, accessor

Now, the package let's you do this:

class User extends \Eloquent implements MappableContract {
    use Mappable;

    protected $maps = ['place_name' => 'place.name'];
    protected $appends = ['place_name'];
}

and that's all. I will be pushing BC breaking change later today, so you may want to wait a bit.

Please or to participate in this conversation.