You could get the latest status for a user via: $user->stauses()->latest()->first();
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.
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');
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.
@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();
}
}
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.