Как группирировать вывод записей при использовании ActiveDataProvider в Yii2?

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Аватара пользователя
MarkL
Сообщения: 68
Зарегистрирован: 2017.07.05, 20:37

Как группирировать вывод записей при использовании ActiveDataProvider в Yii2?

Сообщение MarkL »

Нужно выводить товар в таком формате:
Изображение

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

Имея дело с обычным массивом - это не было бы проблемой:

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

<?php foreach ($groups as $group): ?>
<div>
    <h1><?php echo $group['name'] ?></h1>
    <div>
        <table>
            <?php foreach ($group['products'] as $product): ?>
            <tr>
                <td><?php echo $product['name'] ?></td>
                <td><?php echo $product['price'] ?></td>
            </tr>
            <?php endforeach; ?>
        </table>
    </div>
</div>
<?php endforeach; ?>
Но нам нужна возможность фильтрации/сортировки, поэтому нужен ActiveDataProvider, данные которого оформляются с помощью ListView/GridView.

Из идей только костыли:

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

<?php foreach ($groups as $group): ?>
    <h1><?php echo $group['name'] ?></h1>
    <?php
        echo \yii\widgets\ListView::widget([
            'dataProvider' => new ActiveDataProvider([
                'query' => $group->products,
            ]),
            'layout' => "{items}",
            'itemView' => '@frontend/views/_parts/_order-search-item',
        ])
    ?>
<?php endforeach; ?>
Но он имеет кучу побочных эффектов, как минимум - лишние COUNT SQL-запросы. Как добиться нужного эффекта без костылей?
Аватара пользователя
MarkL
Сообщения: 68
Зарегистрирован: 2017.07.05, 20:37

Re: Как группирировать вывод записей при использовании ActiveDataProvider в Yii2?

Сообщение MarkL »

Может, просто отказаться от ActiveDataProvider или же GridView/ListView, при этом сохранив функционал фильтрации?
unknownby
Сообщения: 747
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Как группирировать вывод записей при использовании ActiveDataProvider в Yii2?

Сообщение unknownby »

MarkL писал(а): 2022.05.24, 16:32 Может, просто отказаться от ActiveDataProvider или же GridView/ListView, при этом сохранив функционал фильтрации?
GridView - отображение моделей в виде списка.
ListView - отображение моделей со своим личным представлением.

Первый виджет больше для админ панели, а второй для пользовательского интерфейса.

Какая фильтрация вам нужна? В первом виджете фильтрация есть встроенная в виджете, во втором случае свою фильтрацию делаете.
Аватара пользователя
MarkL
Сообщения: 68
Зарегистрирован: 2017.07.05, 20:37

Re: Как группирировать вывод записей при использовании ActiveDataProvider в Yii2?

Сообщение MarkL »

unknownby писал(а): 2022.06.14, 11:34
MarkL писал(а): 2022.05.24, 16:32 Может, просто отказаться от ActiveDataProvider или же GridView/ListView, при этом сохранив функционал фильтрации?
GridView - отображение моделей в виде списка.
ListView - отображение моделей со своим личным представлением.

Первый виджет больше для админ панели, а второй для пользовательского интерфейса.

Какая фильтрация вам нужна? В первом виджете фильтрация есть встроенная в виджете, во втором случае свою фильтрацию делаете.
Как с помощью ListView сделать группировать записи по категориям, при этом выводя имя это категории?


Мне надо чтобы товар разделялся по категориям, при этом заголовок категорий выводить.

Чтобы было так:
Изображение

А не так:
Изображение
unknownby
Сообщения: 747
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Как группирировать вывод записей при использовании ActiveDataProvider в Yii2?

Сообщение unknownby »

MarkL писал(а): 2022.06.30, 19:45 Как с помощью ListView сделать группировать записи по категориям, при этом выводя имя это категории?
Мне надо чтобы товар разделялся по категориям, при этом заголовок категорий выводить.
Чтобы было так:
Вы видимо не понимаете разницы между ListView и GridView.

ListView - выводит каждый раз представление в той форме, которую вы ему задали, т.е. вы можете нарисовать для одного товара один блок и если у вас 6 товаров, то выведет 6 красивых блоков.
GridView - выводит товары в виде списка, таблицы. В нем есть возможность группировки, которая скорее всего вам и нужна.

Попробуйте всё же использовать GridView, если задача ещё актуальна :D
Аватара пользователя
MarkL
Сообщения: 68
Зарегистрирован: 2017.07.05, 20:37

Re: Как группирировать вывод записей при использовании ActiveDataProvider в Yii2?

Сообщение MarkL »

unknownby, нет, Вы игнорируете полное прочтение сообщения и осмысление проблемы...
SiZE, спасибо, похоже на выход.
unknownby
Сообщения: 747
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Как группирировать вывод записей при использовании ActiveDataProvider в Yii2?

Сообщение unknownby »

MarkL писал(а): 2022.07.28, 14:57 unknownby, нет, Вы игнорируете полное прочтение сообщения и осмысление проблемы...
SiZE, спасибо, похоже на выход.
Вам подошел ответ от SiZE, в котором он дал ссылку на свойство GridView.
Я посоветовал также использовать GridView.
Вам нужно внимательней быть ;)

P.S.
Чтоб не быть голословным.
Вот как сейчас у вас https://prnt.sc/j-qUxQBHpLXE
А вот так я предлагал вам сделать https://prnt.sc/lVtI3Ih7uKKa

В первом случае было

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

	      [
                'attribute' => 'menu_parent_id',
                'value' => function ($model) {
                    return $model->menuParent->menu_name;
                },
                'format' => 'raw',
                'filterType' => GridView::FILTER_SELECT2,
                'filter' => ArrayHelper::map(Menu::find()->all(), 'menu_id', 'menu_name'),
                'filterWidgetOptions' => [
                    'pluginOptions' => ['allowClear' => true],
                ],
                'filterInputOptions' => ['placeholder' => \Yii::t('main', 'Any')],
            ],
Вот корректировки под виджет GirdView от картика

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

            [
                'attribute' => 'menu_parent_id', 
                'width' => '310px',
                'value' => function ($model) {
                    return $model->menuParent->menu_name;
                },
                'format' => 'raw',
                'filterType' => GridView::FILTER_SELECT2,
                'filter' => ArrayHelper::map(Menu::find()->all(), 'menu_id', 'menu_name'),
                'filterWidgetOptions' => [
                    'pluginOptions' => ['allowClear' => true],
                ],
                'filterInputOptions' => ['placeholder' => 'Any supplier'],
                'group' => true,  // enable grouping,
                'groupedRow' => true,                    // move grouped column to a single grouped row
                'groupOddCssClass' => 'kv-grouped-row',  // configure odd group cell css class
                'groupEvenCssClass' => 'kv-grouped-row', // configure even group cell css class
            ],
Видимо вам проще написать сюда и тут ждать ответа.
Аватара пользователя
MarkL
Сообщения: 68
Зарегистрирован: 2017.07.05, 20:37

Re: Как группирировать вывод записей при использовании ActiveDataProvider в Yii2?

Сообщение MarkL »

unknownby, благодарю за пример решения проблемы.

Однако контексте данной ситуации, боюсь что применение GridView сложно, поскольку:
1. У каждого блока специфическая вёрстка.
2. У каждой группы товаров есть своя подгрузка.

Увы, не было возможности приложить это наглядно — возможно, это позволило бы легче понять что к чему. Но те у кого GridView действительно будет проще.

Касательно сообщений не по теме:
Вам подошел ответ от SiZE, в котором он дал ссылку на свойство GridView.
Я посоветовал также использовать GridView.
Вам нужно внимательней быть ;)
Призываю Вас внимательно почитать моё сообщение:
SiZE, спасибо, похоже на выход.
Я нигде не указывал, что ответ именно подошёл. При беглом осмотре — показалось, что это может решить заявленную проблему.
Видимо вам проще написать сюда и тут ждать ответа.
Да, жду-недождусь поместить в проект код с отключенной фильтрацией опасного содержимого, отсутствием тайп-хинтинга в коллбеке при свойствах с избыточным контекстом в наименовании.

---------------------------------------------------------------------------
Пока такое беглое решение, однако содержит хардкод — $model должен содержать объект, который имеет публичное свойство с объектом $group, который в свою очередь содержать публичное свойство $name.

По завершению работ, приложу полноценный вариант.

Промежуточный:

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

<?php

namespace common\widgets;

use yii\helpers\Html;
use yii\widgets\ListView;

class GroupListView extends ListView
{

    /**
     * @var callable Callable which will be used to generate the group header content.
     * The signature of this callable should be: `function ($group, $groupCount, $widget)`.
     */
    public $groupHeader;

    public function renderItems()
    {
        $models = $this->dataProvider->getModels();
        $keys = $this->dataProvider->getKeys();
        $groups = [];
        
        foreach ($models as $index => $model) {
            $key = $keys[$index];
            $groupName = $model->group->name;
            if (!isset($groups[$groupName])) {
                if ($this->groupHeader !== null) {
                    $groups[$groupName] = call_user_func($this->groupHeader, $groupName, count($models), $this);
                } else {
                    $groups[$groupName] = Html::tag('h2', $groupName);
                }
            }
            $groups[$groupName] .= $this->renderItem($model, $key, $index);
        }

        return implode($this->separator, $groups);
    }

}

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

<?php echo GroupListView::widget([
    'dataProvider' => $dataProvider,
    'itemView' => '_item-list-test',
    'groupHeader' => function ($group) {
        return Html::tag('h2', $group);
    },
]);
Ответить