t-alexashka
@t-alexashka
Сразу пишу legacy код

Как настроить фильтр и сортировку по связанным таблицам?

Привет друзья!

У меня есть модель User и UserSearch(для gridview). в User есть связь с таблицей балансов Balance:
/**
     * Внешняя связь с таблицей балансов
     */
    public function getBalance()
    {
        return $this->hasMany(Balance::className(), ['user_id' => 'id'])->sum('summ');
    }

т.е. в гридвью я вывожу текущую сумму баланса юзера. Вывод работает, но как мне сделать чтобы работал и фильтр для поиска и сортировка по балансу? В UserSearch сделал так:
// Если в фильтре был передан баланс
            if($this->balance) {
                $query->joinWith(['balance' => function ($q) {
                    $q->where('sum(balance.summ) = ' . $this->balance);
                }]);
            }

и получаю бяку:
common\models\User has no relation named "balance".

в User и UserSearch public $balance объявлены, в function rules добавлены.
  • Вопрос задан
  • 506 просмотров
Пригласить эксперта
Ответы на вопрос 3
qonand
@qonand
Software Engineer
Как сделать фильтрацию и сортировку по связанным данным довольно подробно описано в документации
что касается конкретно Вашей ошибки - то тут ничего удивительного у Вас есть свойство $balance и реляция с таким же именем, которая так же доступна как свойство. В результате у Вас получается два свойства с одним именем - одно объявленное Вами, второе - "магическое" на основе реляции.
Выход: или переименуйте реляцию или свое свойство
Ответ написан
slo_nik
@slo_nik Куратор тега Yii
Доброе утро.
Покажите, именно, как Вы фильтруете в поисковой модели.
Если настроить нужно по разным моделям фильтрацию, то Вам надо ещё создать псевдонимы таблиц.
Покажу на своём примере.
Мне требовалось в маршрутах сделать поиск по городам.
В модели "маршруты" создал публичное свойство "$city_id;". Так же есть связующая таблица, где маршруты связаны с городами. В самом запросе добавил связь и joinWith().
$query = Routes::find()
            ->from(['r' => Routes::tableName()])
            ->with(['city', 'routesCities', 'price'])
            ->joinWith([
                'city' => function(ActiveQuery $query){
                    $query->from(['rc1' => Cities::tableName()]);
                }
            ])
            ->joinWith([
                'routesCities' => function(ActiveQuery $query){
                    $query->from(['rc2' => RoutesCities::tableName()]);
                }
            ])

В этом запросе я делаю псевдоним для таблицы маршрутов, для таблицы city и связующей таблицы.
Соответственно получаю три псевдонима "r" - маршруты, "rc1" - города, "rc2" - связующая таблица, хранится привязка города к маршруту.
И тогда в фильтрации пишу следующее:
$query->andFilterWhere([
            'r.id' => $this->id,
            /*****/
            'rc1.id' => $this->city_id, // фильтрую по id города.
        ]);

И в GridView делаю саму колонку фильтра, вывожу через запятую города, через которые проходит маршрут.
[
                'attribute' => 'city_id',
                'label' => "Города",
                'filter' => Cities::find()->select(['title', 'id'])->indexBy('id')->orderBy(['title' => SORT_ASC])->column(),
                'value' => function(Routes $routes){
                     return implode(',', ArrayHelper::map($routes->city, 'id', 'title'));
                }
            ],
Ответ написан
Комментировать
webinar
@webinar Куратор тега Yii
Учим yii: https://youtu.be/-WRMlGHLgRg
в User и UserSearch public $balance объявлены

вот тут и проблема, так как Вы объявили в UserSearch public $balance то и получили в $this->balance строку или число, а не связь как ожидается. Так что просто переименуйте или связь или переменную публичную. Что бы они по разному назывались.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы