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

tecnoe's avatar

Laravel belongsToMany fetch one.

Can someone guide me with the following? I have a many to many relationship in the following way.

Tables:

1- users. 2- user_status. 3- status_type.

Relations

// App\User

public function statuses(){
        return $this->belongsToMany('App\StatusType', 'user_statuses', 'user_id', 'type_id');
}
// App\StatusType

public function users(){
    return $this->belongsToMany('App\User', 'user_statuses', 'type_id', 'user_id');
  }

But I am in the need to get only one record in this case the last record, do you have any idea.

0 likes
5 replies
Talinon's avatar

You could get the latest status for a user via: $user->stauses()->latest()->first();

tecnoe's avatar

Yes, that's right, but I am making an API and I want to eager loading the result. I am tried like this creating an intermediate Model 'App\UserStatus' with belongsTo relations and it works, but I do not know if there is a cleaner way to do it, something like hasOneThrough a pivot table or using an Eloquent Macro.

// App\UserStatus 

public function users(){
        return $this->belongsTo('App\User', 'user_id', 'id');
 }


// App\User
return $this->hasOne('App\UserStatus', 'user_id', 'id')
            ->select([
                'user_statuses.id',
                'user_statuses.type_id',
                'user_statuses.user_id',
                'user_status_types.name',
                'user_status_types.color',
                'user_status_types.notes',
                'user_status_types.available',
                'user_statuses.created_at',
                'user_statuses.updated_at'
            ])
            ->join('user_status_types', 'user_status_types.id', '=', 'user_statuses.type_id')
            ->orderBy('user_statuses.id', 'desc');

staudenmeir's avatar

Laravel 5.8 will have a HasOneThrough relationship that you can use for this.

Until then, you could copy the code into your application. There are also Composer packages that provide this functionality.

2 likes
tecnoe's avatar

@STAUDENMEIR - @staudenmeir, Thanks for the reply. Here is how I include the HasOneThrough in L5.7.

But I still have one more question, It is posible to add pivot columns of the intermediate model, Can you guide me in the right direction.

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use App\Libs\HasOneThrough;

trait CustomRelation
{
    /**
     * Define a has-one-through relationship.
     *
     * @param  string  $related
     * @param  string  $through
     * @param  string|null  $firstKey
     * @param  string|null  $secondKey
     * @param  string|null  $localKey
     * @param  string|null  $secondLocalKey
     * @return \Illuminate\Database\Eloquent\Relations\HasOneThrough
     */
    public function hasOneThrough($related, $through, $firstKey = null, $secondKey = null, $localKey = null, $secondLocalKey = null)
    {
        $through = new $through;
        $firstKey = $firstKey ?: $this->getForeignKey();
        $secondKey = $secondKey ?: $through->getForeignKey();
        return $this->newHasOneThrough(
            $this->newRelatedInstance($related)->newQuery(), $this, $through,
            $firstKey, $secondKey, $localKey ?: $this->getKeyName(),
            $secondLocalKey ?: $through->getKeyName()
        );
    }
    /**
     * Instantiate a new HasOneThrough relationship.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @param  \Illuminate\Database\Eloquent\Model  $farParent
     * @param  \Illuminate\Database\Eloquent\Model  $throughParent
     * @param  string  $firstKey
     * @param  string  $secondKey
     * @param  string  $localKey
     * @param  string  $secondLocalKey
     * @return \Illuminate\Database\Eloquent\Relations\HasOneThrough
     */
    protected function newHasOneThrough(Builder $query, Model $farParent, Model $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey)
    {
        return new HasOneThrough($query, $farParent, $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey);
    }

}
<?php

namespace App\Libs;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\Concerns\SupportsDefaultModels;

use Illuminate\Database\Eloquent\Relations\HasManyThrough;


class HasOneThrough extends HasManyThrough
{
    use SupportsDefaultModels;

    /**
     * Get the results of the relationship.
     *
     * @return mixed
     */
    public function getResults()
    {
        return $this->first() ?: $this->getDefaultFor($this->farParent);
    }

    /**
     * Initialize the relation on a set of models.
     *
     * @param  array   $models
     * @param  string  $relation
     * @return array
     */
    public function initRelation(array $models, $relation)
    {
        foreach ($models as $model) {
            $model->setRelation($relation, $this->getDefaultFor($model));
        }

        return $models;
    }

    /**
     * Match the eagerly loaded results to their parents.
     *
     * @param  array   $models
     * @param  \Illuminate\Database\Eloquent\Collection  $results
     * @param  string  $relation
     * @return array
     */
    public function match(array $models, Collection $results, $relation)
    {
        $dictionary = $this->buildDictionary($results);

        // Once we have the dictionary we can simply spin through the parent models to
        // link them up with their children using the keyed dictionary to make the
        // matching very convenient and easy work. Then we'll just return them.
        foreach ($models as $model) {
            if (isset($dictionary[$key = $model->getAttribute($this->localKey)])) {
                $value = $dictionary[$key];
                $model->setRelation(
                    $relation, reset($value)
                );
            }
        }

        return $models;
    }

    /**
     * Make a new related instance for the given model.
     *
     * @param  \Illuminate\Database\Eloquent\Model  $parent
     * @return \Illuminate\Database\Eloquent\Model
     */
    public function newRelatedInstanceFor(Model $parent)
    {
        return $this->related->newInstance();
    }
}
staudenmeir's avatar

It's possible, but the result won't contain a pivot relationship model as you get with BelongsToMany relationship.

How is your relationship defined and how are you using it?

Please or to participate in this conversation.