Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yii2 GridView with ArrrayDataProvider search

Tags:

php

yii2

I need help with search model for ArrayDataProvider. Let's say i have an array:

$cities = [
    ['city' => "Chicago", 'year' => 1984],
    ['city' => "Washington", 'year' => 2001],
    ['city' => Manchester", 'year' => 1997],
    //and so on...
];

I create an ArrayDataProvider:

$provider = new \yii\data\ArrayDataProvider([
    'allModels' => $catalog,
    'sort' => [
        'attributes' => ['city', 'year'],
    ],
]); 

Then I create a GridView:

echo \yii\grid\GridView::widget([
        'dataProvider' => $provider,
        'filterModel' => (new LibrarySearchModel()),
        'columns' => $columns,
        'showHeader' => true,
        'summary' => false,
    ]);

All works fine, but i need a filtering in GridView. There is no option to use ActiveDataProvider and I cant find any tutorial how to filter a data in ArrayDataProvider. Can someone help me with code for filter model or recomend the docs for my case?

like image 808
Teo Avatar asked Jan 02 '23 17:01

Teo


1 Answers

This is example of how to use ArrayDataProvider with filters in the GridView.

Let's create simple action.

public function actionExample()
{
    $data = new \app\models\Data();
    $provider = $data->search(Yii::$app->request->get());

    return $this->render('example', [
        'provider' => $provider,
        'filter' => $data,
    ]);
}

This is classic Yii 2 approach to the GridView so I will not explain it (you can find details in the Guide linked above).

Now the view.

<?php

echo \yii\grid\GridView::widget([
    'dataProvider' => $provider,
    'filterModel' => $filter,
    'columns' => [
        'name',
        'code',
    ],
]);

Again, nothing different from the ActiveDataProvider approach. As you can see here we are expecting two columns: name and code - these will be defined below.

Data model.

Prepare the model that will handle the data source. Explanation is given in the comments.

<?php

namespace app\models;

use yii\base\Model;

/**
 * Our data model extends yii\base\Model class so we can get easy to use and yet 
 * powerful Yii 2 validation mechanism.
 */
class Data extends Model
{
    /**
     * We plan to get two columns in our grid that can be filtered.
     * Add more if required. You don't have to add all of them.
     */
    public $name;
    public $code;

    /**
     * Here we can define validation rules for each filtered column.
     * See http://www.yiiframework.com/doc-2.0/guide-input-validation.html
     * for more information about validation.
     */
    public function rules()
    {
        return [
            [['name', 'code'], 'string'],
            // our columns are just simple string, nothing fancy
        ];
    }

    /**
     * In this example we keep this special property to know if columns should be 
     * filtered or not. See search() method below.
     */
    private $_filtered = false;

    /**
     * This method returns ArrayDataProvider.
     * Filtered and sorted if required.
     */
    public function search($params)
    {
        /**
         * $params is the array of GET parameters passed in the actionExample().
         * These are being loaded and validated.
         * If validation is successful _filtered property is set to true to prepare
         * data source. If not - data source is displayed without any filtering.
         */
        if ($this->load($params) && $this->validate()) {
            $this->_filtered = true;
        }

        return new \yii\data\ArrayDataProvider([
            // ArrayDataProvider here takes the actual data source
            'allModels' => $this->getData(),
            'sort' => [
                // we want our columns to be sortable:
                'attributes' => ['name', 'code'],
            ],
        ]);
    }

    /**
     * Here we are preparing the data source and applying the filters
     * if _filtered property is set to true.
     */
    protected function getData()
    {
        $data = [
            ['name' => 'Paul', 'code' => 'abc'],
            ['name' => 'John', 'code' => 'ade'],
            ['name' => 'Rick', 'code' => 'dbn'],
        ];

        if ($this->_filtered) {
            $data = array_filter($data, function ($value) {
                $conditions = [true];
                if (!empty($this->name)) {
                    $conditions[] = strpos($value['name'], $this->name) !== false;
                }
                if (!empty($this->code)) {
                    $conditions[] = strpos($value['code'], $this->code) !== false;
                }
                return array_product($conditions);
            });
        }

        return $data;
    }
}

The filtering in this example is handled by the array_filter function. Both columns are filtered "database LIKE"-style - if column value contains the searched string the data array row is not removed from the source.

To make it work like and conditions in ActiveDataProvider we put boolean result of every column check in the $conditions array and return product of that array in array_filter.

array_product($conditions) is equivalent of writing $conditions[0] && $conditions[1] && $conditions[2] && ...

This all results in the filterable and sortable GridView widget with two columns.

like image 177
Bizley Avatar answered Jan 05 '23 14:01

Bizley