Фильтр и поиск в GridView

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
ViRuS-X
Сообщения: 31
Зарегистрирован: 2017.04.19, 01:33

Фильтр и поиск в GridView

Сообщение ViRuS-X »

Здравствуйте. Есть колонка в гридвью в которой данные представлены внешним ключем к другой таблице. Проблему вывода данных из этой таблицы, вместо ключа я решил просто:

['attribute' => 'autor', 'value' => function($model){
return $model->user->username;
}],

Теперь данные выводятся не малозначимыми айдишниками, а как положено - имена пользователей, к которым эти айди относятся.

Проблема: как вы наверное уже поняли, поиск все так же осуществляется исключительно по айдишнику из основной таблицы, а по имени пользователя из связанной таблицы поиск невозможен. Как решить эту проблему? Заранее спасибо.
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: Фильтр и поиск в GridView

Сообщение girmate »

Все верно, но поиск по связанным таблицам в двух словах не рассказать.
Вам очень сильно поможет google "поиск по связанным данным yii2".
Но еще лучше советую посмотреть: Вебинар от ElisDN (Дмитрий). Там как раз ваша тема рассматривается (Дмитрий всегда очень подробно рассматривает любые вопросы, если покажется удобным - увеличьте скорость просмотра).
Осторожно! Вы общаетесь с новичком ;)
ViRuS-X
Сообщения: 31
Зарегистрирован: 2017.04.19, 01:33

Re: Фильтр и поиск в GridView

Сообщение ViRuS-X »

Все, решил, если кому интересно и может пригодиться, то:
1. Создаем статическую функцию в классе АктивРекорд основной таблицы, которая возвращает все айдишники авторов и подтягивает к ним имена со связанной таблицы соответствующие айдишникам из основной. После формирует массив "id" => "username" и возвращает его. Пример -
public static function getAutorList()
{
$sql = 'SELECT DISTINCT autor, username FROM articles JOIN users ON autor = users.id';
$autors = self::findBySql($sql)->asArray()->all();
$autorList = [];
foreach ($autors as $autor) {
$autorList[$autor['autor']] = $autor['username'];
}
return $autorList;
}
2. Вызывает эту функцию в качестве параметра "filter" нужного столбца в ГридВью. Пример -
['attribute' => 'autor', 'filter' => Articles::getAutorList(), 'value' => function($model){
return $model->user->username;
}],

Все. Теперь не только в столбцах отображаются данные из связанной таблицы, но и в поле поиска в выпадающем списке.
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: Фильтр и поиск в GridView

Сообщение girmate »

И фильтрация работает? А сортировка :D ? А сколько запросов в БД идет по факту?
Последний раз редактировалось girmate 2018.02.13, 22:10, всего редактировалось 1 раз.
Осторожно! Вы общаетесь с новичком ;)
ViRuS-X
Сообщения: 31
Зарегистрирован: 2017.04.19, 01:33

Re: Фильтр и поиск в GridView

Сообщение ViRuS-X »

girmate писал(а): 2018.02.13, 21:55 Все верно, но поиск по связанным таблицам в двух словах не рассказать.
Вам очень сильно поможет google "поиск по связанным данным yii2".
Но еще лучше советую посмотреть: Вебинар от ElisDN (Дмитрий). Там как раз ваша тема рассматривается (Дмитрий всегда очень подробно рассматривает любые вопросы, если покажется удобным - увеличьте скорость просмотра).
Да я смотрю, но все запомнить не реально, а видео которые он пишет огромны и искать в них что-то - та ещё задачка.
ViRuS-X
Сообщения: 31
Зарегистрирован: 2017.04.19, 01:33

Re: Фильтр и поиск в GridView

Сообщение ViRuS-X »

girmate писал(а): 2018.02.13, 22:10 И фильтрация работает? А сортировка :D ? А сколько запросов в БД идет по факту?
Все извлекается одним запросом, как сами видите, фильтрация полностью работает. В ГридВью появляется ДропДавнЛист где все авторы по именам, а не айдишникам.
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: Фильтр и поиск в GridView

Сообщение girmate »

ViRuS-X писал(а): 2018.02.13, 22:10 Да я смотрю, но все запомнить не реально, а видео которые он пишет огромны и искать в них что-то - та ещё задачка.
Некоторые его видео я пересматривал по 6(!) раз. И вы не поверите, поскольку я еще очень начинающий - я всегда находил что-то новое при каждом новом просмотре. Иногда даже полезно спустя полгода просто пересмотреть видео. Я всегда, там где можно смотрю на скорости +20-25%. Просто Дмитрий старается не упустить ничего важного. И трудно найти золотую середину. Одним материал легкий - им только нюансы показать. А другим, наоборот, нужно разжевать.
В свое время прошел его курс по ООП. Он очень сильно мне помог (не реклама). Теперь я может и много где еще буду лапшекодить. Но на некоторые вещи взглянул совершенно по-новому. И если до курса от Дмитрия по ООП я любые рецепты смотрел и радовался, то сейчас есть те видео, которые считаю вредными (например "yii для блондинок" (или как-то так), тот что на youtube). Такие видео сразу закрываю - они вредят (пусть автор курса простит меня). Нужны сервисы, репозитории и прочие полезные фишки, чтобы код был легко читаемым, тестируемым, в перспективе без особых сложностей расширяемым.

Как-то я сделал знакомому интернет-магазин. После того, как прошел курс по ООП стало стыдно за свой магазин. Одновременно получил разочарование - мне оказалось не то чтобы далеко до SamDark, zelenin, ElisDN и многих-многих других товарищей, а мне до них вообще никогда! Не в этой жизни))
Последний раз редактировалось girmate 2018.02.13, 22:25, всего редактировалось 6 раз.
Осторожно! Вы общаетесь с новичком ;)
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: Фильтр и поиск в GridView

Сообщение girmate »

ViRuS-X писал(а): 2018.02.13, 22:12
girmate писал(а): 2018.02.13, 22:10 И фильтрация работает? А сортировка :D ? А сколько запросов в БД идет по факту?
Все извлекается одним запросом, как сами видите, фильтрация полностью работает. В ГридВью появляется ДропДавнЛист где все авторы по именам, а не айдишникам.
Возможно. Но я помню сортировка не работает по связанным полям. Нужно еще немного колдовать и настраивать. И обратите внимание сколько у вас запросов идет к БД. Если не делаете жадную загрузку - то их будет равно количеству записей на странице в гриде +1 как минимум (не считая других запросов, например схемы). А это очень много.
Осторожно! Вы общаетесь с новичком ;)
ViRuS-X
Сообщения: 31
Зарегистрирован: 2017.04.19, 01:33

Re: Фильтр и поиск в GridView

Сообщение ViRuS-X »

girmate писал(а): 2018.02.13, 22:17
ViRuS-X писал(а): 2018.02.13, 22:12
girmate писал(а): 2018.02.13, 22:10 И фильтрация работает? А сортировка :D ? А сколько запросов в БД идет по факту?
Все извлекается одним запросом, как сами видите, фильтрация полностью работает. В ГридВью появляется ДропДавнЛист где все авторы по именам, а не айдишникам.
Возможно. Но я помню сортировка не работает по связанным полям. Нужно еще немного колдовать и настраивать. И обратите внимание сколько у вас запросов идет к БД. Если не делаете жадную загрузку - то их будет равно количеству записей на странице в гриде +1 как минимум (не считая других запросов, например схемы). А это очень много.
Сортировка не работает, но она мне и не нужна здесь. Чтобы все извлекалось одним запросом в модели поиска нужно вместо $query = Articles::find() написать $query = Articles::find()->with('user')
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: Фильтр и поиск в GridView

Сообщение girmate »

Сортировка - пока не нужна). Добейте этот вопрос, рано или поздно пригодится, будете подсматривать.
Осторожно! Вы общаетесь с новичком ;)
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: Фильтр и поиск в GridView

Сообщение girmate »

ViRuS-X писал(а): 2018.02.13, 22:34 $query = Articles::find()->with('user')
И если честно, я уже сам забыл, в каких случаях нужен with, а в каких joinwith. Там точно какое-то важное отличие в использовании, но какое хоть убей - не помню.
Осторожно! Вы общаетесь с новичком ;)
ViRuS-X
Сообщения: 31
Зарегистрирован: 2017.04.19, 01:33

Re: Фильтр и поиск в GridView

Сообщение ViRuS-X »

girmate писал(а): 2018.02.13, 22:36
ViRuS-X писал(а): 2018.02.13, 22:34 $query = Articles::find()->with('user')
И если честно, я уже сам забыл, в каких случаях нужен with, а в каких joinwith. Там точно какое-то важное отличие в использовании, но какое хоть убей - не помню.
Разобрался и все сделал как положено, без костылей. Спасибо за наводку!
Аватара пользователя
maleks
Сообщения: 1985
Зарегистрирован: 2012.12.26, 12:56

Re: Фильтр и поиск в GridView

Сообщение maleks »

['attribute' => 'autor', 'value' => function($model){
return $model->user->username;
}],
Можно так:

Код: Выделить всё

['attribute' => 'autor', 'value' => 'user.username'],
ViRuS-X писал(а): 2018.02.14, 01:51 Разобрался и все сделал как положено, без костылей. Спасибо за наводку!
А что конкретно и как вы доделали?
Yii2 universal module sceleton - for basic and advanced templates
ViRuS-X
Сообщения: 31
Зарегистрирован: 2017.04.19, 01:33

Re: Фильтр и поиск в GridView

Сообщение ViRuS-X »

maleks писал(а): 2018.02.14, 08:58
['attribute' => 'autor', 'value' => function($model){
return $model->user->username;
}],
Можно так:

Код: Выделить всё

['attribute' => 'autor', 'value' => 'user.username'],
ViRuS-X писал(а): 2018.02.14, 01:51 Разобрался и все сделал как положено, без костылей. Спасибо за наводку!
А что конкретно и как вы доделали?
Вот здесь https://nix-tips.ru/yii2-sortirovka-i-f ... olyam.html - правильный подход.
panda
Сообщения: 14
Зарегистрирован: 2017.07.18, 16:16

Re: Фильтр и поиск в GridView

Сообщение panda »

girmate писал(а): 2018.02.13, 22:36 в каких случаях нужен with, а в каких joinwith. Там точно какое-то важное отличие в использовании, но какое хоть убей - не помню.
на практике вывела для себя такое правило:
если нужно в условии запроса использовать поля из связанной таблицы, то joinWith
если не нужно, то with

Есть нюансы с количеством записей, но обычно оно не играет особой роли
steaze
Сообщения: 30
Зарегистрирован: 2017.01.28, 21:25

Re: Фильтр и поиск в GridView

Сообщение steaze »

Каноническое решение Вам подсказал ViRuS-X, или с оф.сайта: http://www.yiiframework.com/wiki/621/fi ... w-yii-2-0/.
Но чем больше связанных полей, тем больше запросов вы получите (см.дебаггер). Разумеется в продакшене такие запросы кэшируются, но я решил сделать всё одним запросом, как это обычно делается в классических БД. Может, кому пригодится. На примере таблицы "активных пользователей". Модели, ActiveQuery, Search и View создавались генератором gii.

Есть модель UserActiv. Добавляем в UserActivQuery подключение всех нужных таблиц:

Код: Выделить всё

    public function joinAll()
    {
        return $this->alias('ua')
            ->select('ua.*, u.username, pg.objectname pagename')
            ->innerJoin(User::tableName() . ' u', 'ua.user_id = u.id')
            ->innerJoin(Page::tableName() . ' pg', 'ua.page_id = pg.id');
    }
Чтобы в полной мере использовать подключённые столбцы, добавляем переменные в класс (pagename - алиас):

Код: Выделить всё

class UserActiv extends \yii\db\ActiveRecord
{
    public $pagename;
    public $username;
    ...

Далее в стандартном сгенерированном UserActivSearch меняем метод search (привожу полностью). Здесь мы переопределяем аттрибуты:

Код: Выделить всё

   public function search($params)
    {
        $query = UserActiv::find()->joinAll();
        $dataProvider = new ActiveDataProvider([ 'query' => $query, ]);

        $dataProvider->setSort([
            'attributes' => [
                'user_agent',
                'link', 
                'ip_address',
                'last_action',
                'username' => [
                    'asc' => ['u.username' => SORT_ASC],
                    'desc' => ['u.username' => SORT_DESC],
                    'label' => 'Пользователь',
                ],
                'pagename' => [
                    'asc' => ['pg.objectname' => SORT_ASC],
                    'desc' => ['pg.objectname' => SORT_DESC],
                    'label' => 'Ресурс',
                ],
            ],
            'defaultOrder' => ['last_action' => SORT_DESC],
       ]);

        $this->load($params);

        if (!$this->validate()) {
            return $dataProvider;
        }

        $query->andFilterWhere([
            'last_action' => $this->last_action,
        ]);
        
	// здесь выполняем отбор
        $query->andFilterWhere(['like', 'user_agent', $this->user_agent])
        	// это наши связанные поля
            ->andFilterWhere(['like', 'pg.objectname', $this->pagename])
            ->andFilterWhere(['like', 'u.username', $this->username])
            ->andFilterWhere(['like', 'ip_address', $this->ip_address])
            ->andFilterWhere(['like', 'link', $this->link])            ;

        return $dataProvider;
    }
Остальное менять не нужно. В GridView в columns просто добавляете переопределённые:

Код: Выделить всё

 <?= GridView::widget([
        'dataProvider' => $dataProvider,
        'filterModel' => $searchModel,
        'columns' => [
            [ 'class' => 'yii\grid\SerialColumn'],
            'last_action',
            // наши связанные поля
            'username',
            'pagename',
            // ..
            'ip_address',
            'link',
            'user_agent',
        ]
    ]);
?>
Пользоваться не обязательно, лично мне такое решение показалось правильным.
rosolovsky
Сообщения: 119
Зарегистрирован: 2014.06.23, 11:44
Откуда: Украина

Re: Фильтр и поиск в GridView

Сообщение rosolovsky »

Кстати, на вашем плохом "yii для блондинок" в ютубе ваш вопрос, который в начале темы, рассматривался! :) И там вроде все понятно и не сложно.
Аватара пользователя
girmate
Сообщения: 1534
Зарегистрирован: 2015.10.27, 12:52

Re: Фильтр и поиск в GridView

Сообщение girmate »

rosolovsky писал(а): 2018.02.15, 00:53 Кстати, на вашем плохом "yii для блондинок" в ютубе ваш вопрос, который в начале темы, рассматривался! :) И там вроде все понятно и не сложно.
Топик не мой, поэтому только догадываюсь, что речь идет о либо о сортировке, либо о join. Я уже реализовывал и то и другое, просто кода под рукой не было - и там, в целом, ничего сверхсложного нету. А "видео для блондинок" плохо не потому, что рассказывают про самые основы, а потому что учат говнокодить, формируют узкое мышление, прививая процедурный, а не ООП-шный подход к программированию. И где-то для бложика, ничего плохого в этом нету. Но, как выражался ElisDN - программирование, ничем не отличающееся от обертки mysql - phpmyadmin и толстые контроллеры, неповоротливые модели с божественными методами, делающие все подряд... Вот это я и имел в виду.
Осторожно! Вы общаетесь с новичком ;)
rosolovsky
Сообщения: 119
Зарегистрирован: 2014.06.23, 11:44
Откуда: Украина

Re: Фильтр и поиск в GridView

Сообщение rosolovsky »

Ну про фильтрацию там рассказано вроде неплохо, как для "блондинок". А так да, ООП подход это не просто так, этим нужно заниматься. :)
Ответить