Laravel Eloquent получает данные из двух таблиц через промежуточную таблицу

У меня есть следующие три таблицы:

users
    id - integer
    name - string

tracker_sessions
    id - integer
    user_id - integer
    geoip_id - integer

tracker_geoip
    id - integer
    country - string

Это мои модели:

class User extends Authenticatable
{
    public function tracker_geoip(){
        return $this->hasManyThrough('App\TrackerGeo', 'App\TrackerSession', 'geoip_id', 'id', 'id');
    }
    public function tracker_sessions(){
        return $this->hasMany('App\TrackerSession');
    }
}

class TrackerGeo extends Model
{
    protected $table = 'tracker_geoip';
}

class TrackerSession extends Model
{
    protected $table = 'tracker_sessions';
}

Можно ли получить этот результат с помощью Eloquent? :

0 => [
     'name' => 'John Smith',
     'geoip' => ['id' => 12, 'country' => 'Greenland']
]

Я пробовал это:

$usersWithGeo = App\User::with('tracker_geoip')->get()->toArray();

Это возвращает массив информации о пользователе, но подмассив tracker_geoip всегда пуст, даже если в таблицах есть записи.


person user3102290    schedule 21.02.2017    source источник
comment
Зачем вам нужна модель для tracker_sessions? Laravel автоматически обрабатывает отношения «многие ко многим».   -  person thefallen    schedule 21.02.2017
comment
@TheFallen на самом деле не использует сводную таблицу. так ему нужна модель   -  person xhulio    schedule 21.02.2017
comment
Вы также пытались использовать метод load(). то есть App\User::load('tracker_geoip');   -  person Oluwatobi Samuel Omisakin    schedule 21.02.2017


Ответы (2)


Глядя на структуру вашей таблицы, отношение для tracker_geoip на самом деле должно быть belongsToMany, а не hasManyThrough.

return $this->belongsToMany('App\TrackerGeo', 'tracker_sessions', 'user_id', 'geoip_id')->distinct();

Надеюсь это поможет!

person Rwd    schedule 21.02.2017
comment
Благодарю вас ! Ваше предложение сработало, но теперь подмассив tracker_geoip имеет много дублирующихся индексов. Он имеет столько же индексов, сколько сеансов пользователя. В любом случае я мог бы получить только один индекс, например: 'tracker_geoip' => ['id' => 12, 'country' => 'Гренландия']. Может быть фильтр с подзапросом? - person user3102290; 21.02.2017
comment
В этом случае вам просто нужно добавить distinct() к вашим отношениям. Я обновил свой ответ, чтобы показать это. - person Rwd; 21.02.2017

попробуйте следующий код (избегая отношений):

class TrackerSession extends Model
{
    public function getGeoipNameAttribute(){
        return TrackerGeo::where('id', $this->attributes['geoip_id'])->first(); //you can stop here or add ->country; to get only the country name
    };
}

Приведенный выше метод извлекает название страны из коллекции TrackerGeo с заданным идентификатором.

Теперь вам нужно получить все сеансы трекера для данного пользователя. Итак, в пользовательской модели мы имеем:

public function getTrackerSessionAttribute(){
    return TrackerSession::where('user_id', %this->attributes['id'])->get() //or first() depends on the number of records you want to retrieve.
}

и на ваш взгляд вы можете сделать следующее:

$user->tracker_session->geoip_name // ->country depends on the return result

если вы получили только 1 запись с помощью метода first() Eloquent или

@foreach($user->tracker_session as $session)
    {{$session->geoip_name}} // {{$session->geoip_name->country}} depends on the return result
@endforeach

обратите внимание, что вы можете получить доступ к коллекциям, используя змеиное имя метода в качестве атрибута основной модели.

person xhulio    schedule 21.02.2017