Страница 2 из 2

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.25, 17:15
zelenin
VaNnOrus писал(а): Админам не нужны удобства, только хардкор? :)
все зависит от задачи. как правило это грид - места нет, а при малом количестве места слайдер даст только неточное ограничение. а в админке как правило нужна точная выборка.

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 11:36
VaNnOrus
Insolita писал(а):попробовала, но штука в том что при изменении select фильтр сразу начинает запрос фильтрации...
Можно попробовать задать validateOnBlur/...OnChange/...OnType false.

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 12:21
Insolita
да можно, мне это в принципе то не нужно было, я чисто так особо не заморачиваясь набросала, на заметочку, вдруг когда понадобится

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 13:08
zelenin
Insolita писал(а):да можно, мне это в принципе то не нужно было, я чисто так особо не заморачиваясь набросала, на заметочку, вдруг когда понадобится
надо добавлять data-pjax="0" тем вещам, на которые не надо вешать pjax

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 13:12
lynicidn
сделайте min и max, и необязательными, тогда знаки сравнения юзер не будет вводить, и вам при валидации меньше проблем

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 13:23
Shappy
В общем... Сделал я behavior, по мне так удобно... Если кто захочет покритиковать - пожалуйста... Кому-то может показаться неудобным...

behavior:

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

<?php

namespace app\modules\admin\common\behaviors;

use yii;
use yii\base\Behavior;
use yii\db\ActiveRecord;
use yii\helpers\Html;

class AdminSignComparison extends Behavior
{
    /**
     * @var $comparisonAttributes array
     * Array of attributes that needed comparison
     */
    public $comparisonAttributes;

    /**
     * @return array
     */
    public function events()
    {
        return [
            ActiveRecord::EVENT_BEFORE_VALIDATE => 'setComparisonAttributes'
        ];
    }

    /**
     * Method before validate, delete comparison characters and sets needed value.
     * @return void
     */
    public function setComparisonAttributes()
    {
        if($this->owner->scenario != 'search')
            return;

        foreach($this->comparisonAttributes as $attribute => $settingsArray)
        {
            if(empty($this->owner->$attribute) || $settingsArray['type'] === false)
                continue;

            if($settingsArray['type'] === 'text')
            {
                $this->comparisonAttributes[$attribute]['comparison'] = '=';
                continue;
            }

            $this->setComparisonCharacters($attribute);
            if($settingsArray['type'] === 'datetime')
                $this->setDatetimeAttribute($attribute);
        }
    }

    /**
     * @param $attribute string
     * Function delete comparison characters and sets comparison characters into $comparisonAttributes
     */
    private function setComparisonCharacters($attribute)
    {
        switch(substr($this->owner->$attribute, 0, 1))
        {
            case '<':
                if(substr($this->owner->$attribute, 1, 1) == '=')
                {
                    $this->owner->$attribute = substr($this->owner->$attribute, 2);
                    $this->comparisonAttributes[$attribute]['comparison'] = '<=';
                }
                else if(substr($this->owner->$attribute, 1, 1) == '>')
                {
                    $this->owner->$attribute = substr($this->owner->$attribute, 2);
                    $this->comparisonAttributes[$attribute]['comparison'] = '<>';
                }
                else
                {
                    $this->owner->$attribute = substr($this->owner->$attribute, 1);
                    $this->comparisonAttributes[$attribute]['comparison'] = '<';
                }
                break;
            case '>':
                if(substr($this->owner->$attribute, 1, 1) == '=')
                {
                    $this->owner->$attribute = substr($this->owner->$attribute, 2);
                    $this->comparisonAttributes[$attribute]['comparison'] = '>=';
                }
                else
                {
                    $this->owner->$attribute = substr($this->owner->$attribute, 1);
                    $this->comparisonAttributes[$attribute]['comparison'] = '>';
                }
                break;
            default:
                if(substr($this->owner->$attribute, 0, 1) === '=')
                    $this->owner->$attribute = substr($this->owner->$attribute, 1);
                $this->comparisonAttributes[$attribute]['comparison'] = '=';
                break;
        }
    }

    /**
     * @param $attribute string
     * Function sets right comparison for datetime and call getComparisonDatetime() to get correct datetime
     */
    private function setDatetimeAttribute($attribute)
    {
        if($this->comparisonAttributes[$attribute]['comparison'] === '=')
            $this->comparisonAttributes[$attribute]['comparison'] = 'between';

        $attributeLength = strlen($this->owner->$attribute);

        if($attributeLength == 4)
        {
            if($this->comparisonAttributes[$attribute]['comparison'] === '=')
                $this->comparisonAttributes[$attribute]['secondAttribute'] = $this->owner->$attribute . '-12-31 23:59:59';
            $this->owner->$attribute = $this->getComparisonDatetime($attribute, 'year', $this->owner->$attribute);
        }
        elseif($attributeLength == 7)
        {
            if($this->comparisonAttributes[$attribute]['comparison'] === '=')
                $this->comparisonAttributes[$attribute]['secondAttribute'] = $this->owner->$attribute . '-' . date('t', strtotime($this->owner->$attribute)) . ' 23:59:59';
            $this->owner->$attribute = $this->getComparisonDatetime($attribute, 'month', $this->owner->$attribute);
        }
        elseif($attributeLength == 10)
        {
            if($this->comparisonAttributes[$attribute]['comparison'] === '=')
                $this->comparisonAttributes[$attribute]['secondAttribute'] = $this->owner->$attribute . ' 23:59:59';
            $this->owner->$attribute = $this->getComparisonDatetime($attribute, 'day', $this->owner->$attribute);
        }
        elseif($attributeLength == 13)
        {
            if($this->comparisonAttributes[$attribute]['comparison'] === '=')
                $this->comparisonAttributes[$attribute]['secondAttribute'] = $this->owner->$attribute . ':59:59';
            $this->owner->$attribute = $this->getComparisonDatetime($attribute, 'hour', $this->owner->$attribute);
        }
        elseif($attributeLength == 16)
        {
            if($this->comparisonAttributes[$attribute]['comparison'] === '=')
                $this->comparisonAttributes[$attribute]['secondAttribute'] = $this->owner->$attribute . ':59';
            $this->owner->$attribute = $this->getComparisonDatetime($attribute, 'minute', $this->owner->$attribute);
        }
        else
            $this->comparisonAttributes[$attribute]['comparison'] = '=';
    }

    /**
     * @param $attribute string
     * @param $period string
     * @param $value string
     * @return string
     *
     * Function sets right comparison for datetime and return correct datetime
     */
    private function getComparisonDatetime($attribute, $period, $value)
    {
        $comparisonDateTime = $value;
        $comparison = $this->comparisonAttributes[$attribute]['comparison'];
        switch($period)
        {
            case 'year':
                if($comparison === '<' || $comparison === '>=')
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . '-01-01 00:00:00'));
                elseif($comparison === '<=' || $comparison === '>')
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . '-12-31 23:59:59'));
                elseif($comparison === '<>' || $comparison === 'between')
                {

                    $this->comparisonAttributes[$attribute]['secondAttribute'] = date('Y-m-d H:i:s', strtotime($value . '-12-31 23:59:59'));
                    $this->comparisonAttributes[$attribute]['comparison'] = $comparison === '<>' ? 'not between' : 'between';
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . '-01-01 00:00:00'));
                }
                break;
            case 'month':
                if($comparison === '<' || $comparison === '>=')
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . '-01 00:00:00'));
                elseif($comparison === '<=' || $comparison === '>')
                {
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . '-' . date('t', strtotime($value)) . ' 23:59:59'));
                }
                elseif($comparison === '<>' || $comparison === 'between')
                {
                    $this->comparisonAttributes[$attribute]['secondAttribute'] = date('Y-m-d H:i:s', strtotime($value . '-' . date('t', strtotime($value)).' 23:59:59'));
                    $this->comparisonAttributes[$attribute]['comparison'] = $comparison === '<>' ? 'not between' : 'between';
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . '-01 00:00:00'));
                }
                break;
            case 'day':
                if($comparison === '<' || $comparison === '>=')
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . ' 00:00:00'));
                elseif($comparison === '<=' || $comparison === '>')
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . ' 23:59:59'));
                elseif($comparison === '<>' || $comparison === 'between')
                {
                    $this->comparisonAttributes[$attribute]['secondAttribute'] = date('Y-m-d H:i:s', strtotime($value . ' 23:59:59'));
                    $this->comparisonAttributes[$attribute]['comparison'] = $comparison === '<>' ? 'not between' : 'between';
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . ' 00:00:00'));
                }
                break;
            case 'hour':
                if($comparison === '<' || $comparison === '>=')
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . ':00:00'));
                elseif($comparison === '<=' || $comparison === '>')
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . ':59:59'));
                elseif($comparison === '<>' || $comparison === 'between')
                {
                    $this->comparisonAttributes[$attribute]['secondAttribute'] = date('Y-m-d H:i:s', strtotime($value . ':59:59'));
                    $this->comparisonAttributes[$attribute]['comparison'] = $comparison === '<>' ? 'not between' : 'between';
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . ':00:00'));
                }
                break;
            case 'minute':
                if($comparison === '<' || $comparison === '>=')
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . ':00'));
                elseif($comparison === '<=' || $comparison === '>')
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . ':59'));
                elseif($comparison === '<>' || $comparison === 'between')
                {
                    $this->comparisonAttributes[$attribute]['secondAttribute'] = date('Y-m-d H:i:s', strtotime($value . ':59'));
                    $this->comparisonAttributes[$attribute]['comparison'] = $comparison === '<>' ? 'not between' : 'between';
                    $comparisonDateTime = date('Y-m-d H:i:s', strtotime($value . ':00'));
                }
                break;
            default:
                $comparisonDateTime = $value;
                break;
        }
        return $comparisonDateTime;
    }

    /**
     * @param yii\db\ActiveQuery $query
     * @return yii\db\ActiveQuery
     *
     * Function return $query with all filters for search
     */
    public function getFiltersForSearch(yii\db\ActiveQuery $query)
    {
        foreach($this->comparisonAttributes as $attribute => $settingsArray)
        {
            if(empty($this->owner->$attribute) || $settingsArray['type'] === false)
                continue;

            if($this->comparisonAttributes[$attribute]['comparison'] === 'between' || $this->comparisonAttributes[$attribute]['comparison'] === 'not between')
                $query->andFilterWhere([
                    $this->comparisonAttributes[$attribute]['comparison'],
                    $this->owner->tableName() . '.' . $attribute,
                    $this->owner->$attribute,
                    $this->comparisonAttributes[$attribute]['secondAttribute']
                ]);
            else
                $query->andFilterWhere([
                    $this->comparisonAttributes[$attribute]['comparison'],
                    $this->owner->tableName() . '.' . $attribute,
                    $this->owner->$attribute
                ]);
        }
        return $query;
    }

    /**
     * @param $attribute string
     * @return string
     *
     * Function return textInput of filter
     */
    public function getFilter($attribute)
    {
        if(isset(Yii::$app->request->get($this->owner->formName(), null)[$attribute]))
            $value = Yii::$app->request->get($this->owner->formName(), null)[$attribute];
        else
            $value = null;
        return Html::textInput($this->owner->formName() . '['.$attribute.']', $value, ['class' => 'form-control']);
    }
}
Как использовать:
1. В моделе добавляем сценарий search. вписываем все поля для массового присваивания (в общем все поля что выводим и по которым есть фильтр):

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

    public function scenarios()
    {
        $scenarios = parent::scenarios();
        $scenarios['search'] = ['id', 'user_id', 'banner_place_id', 'start_datetime', 'end_datetime', 'cost', 'active', 'created_at', 'updated_at'];
        return $scenarios;
    }
2. Прикручиваем бехейвер:

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

public function behaviors()
    {
        return [
            'AdminSignComparison' => [
                'class' => AdminSignComparison::className(),
                'comparisonAttributes' => [
                    'id'=>['type'=>'numeric'],
                    'user_id'=>['type'=>'numeric'],
                    'banner_place_id'=>['type'=>'text'],
                    'start_datetime'=>['type'=>'datetime'],
                    'end_datetime'=>['type'=>'datetime'],
                    'cost'=>['type'=>'numeric'],
                    'created_at'=>['type'=>'datetime'],
                    'updated_at'=>['type'=>'datetime'],
                ]
            ]
        ];
    }
В comparisonAttributes вставляем аттрибуты которые должны использовать сортировку со знаками. И пишем каждому тип, numeric или datetime. В зависимости от поля.

3. В функцию search добавляем сценарий до валидации:

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

$this->setScenario('search');
И с запросом работаем так:

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

$query = $this->getBehavior('AdminSignComparison')->getFiltersForSearch($query);
        $query->andFilterWhere([
            'active_banners.active' => $this->active,
            'active_banners.banner_place_id' => $this->banner_place_id
        ]);
т.е. в моем случае первой строкой забираем условия по тем полям, для которых нужны сравнения.

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

$query = $this->getBehavior('AdminSignComparison')->getFiltersForSearch($query);
После этого руками указываю поля, для которых эти сравнения не нужны.

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

$query->andFilterWhere([
            'active_banners.active' => $this->active,
            'active_banners.banner_place_id' => $this->banner_place_id
        ]);
4. Поля во вьюхе выводим след. образом:

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

[
                'attribute'=>'id',
                'filter' => $searchModel->getBehavior('AdminSignComparison')->getFilter('id')
            ],
П.с. поля datetime храняться в Y-m-d H:i:s. Я их не переделывал, так и вывожу...
Все. В чем профит... Во-первых integer, double, и т.д. сравниваются <, <=, >, >=, <>, =. Так же сравнивать можно и поля с datetime типом. Так же можно писать например: 2014 (все поля за 2014 год), <2014 (все поля до 2014 года) и т.д. Так же можно писать и <2014-02 (Все меньше февраля 2014) и т.д. по дням часам минутам...
Сильно строго не судите, критика принимается...

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 13:27
zelenin
всю работу с датами я бы вынес в отдельный метод и использовал бы DateTime с sub/add

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 13:42
Shappy
zelenin писал(а):всю работу с датами я бы вынес в отдельный метод и использовал бы DateTime с sub/add
Вообще использовать DateTime наверно было бы разумней... А метод с датами жирным слишком был, разделил его на два...

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 14:23
Insolita
zelenin писал(а):
Insolita писал(а):да можно, мне это в принципе то не нужно было, я чисто так особо не заморачиваясь набросала, на заметочку, вдруг когда понадобится
надо добавлять data-pjax="0" тем вещам, на которые не надо вешать pjax
так это для ссылок работает , а не для селектов, и там не pjax - там подвешенный скрипт от фильтра отрабатывает,

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 15:15
zelenin
Insolita писал(а):
zelenin писал(а):
Insolita писал(а):да можно, мне это в принципе то не нужно было, я чисто так особо не заморачиваясь набросала, на заметочку, вдруг когда понадобится
надо добавлять data-pjax="0" тем вещам, на которые не надо вешать pjax
так это для ссылок работает , а не для селектов, и там не pjax - там подвешенный скрипт от фильтра отрабатывает,
у грида есть клиентские опции, где можно указать filterSelector, который по умолчанию "#$id input, #$id select"
Можно указать что-то типа "#$id input:not([data="not-filter"]), #$id select:not([data="not-filter"])"

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 16:43
VaNnOrus
Shappy писал(а):П.с. поля datetime храняться в Y-m-d H:i:s. Я их не переделывал, так и вывожу...
Все. В чем профит... Во-первых integer, double, и т.д. сравниваются <, <=, >, >=, <>, =. Так же сравнивать можно и поля с datetime типом. Так же можно писать например: 2014 (все поля за 2014 год), <2014 (все поля до 2014 года) и т.д. Так же можно писать и <2014-02 (Все меньше февраля 2014) и т.д. по дням часам минутам...
Сильно строго не судите, критика принимается...
Критика уже была - юзабилити страдает.
Если уж совсем лень прикручивать ползунки - два инпута "от" и "до" - для пользователя и то лучше будет.
Дата так же от и до, но обязательно человеческими календарями. Если это сайт не для программистов - Ваши 2014-12-21 добрая половина пользователей просто не поймет, потому что так не принято писать даты в жизни.

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 17:25
Shappy
VaNnOrus писал(а):
Shappy писал(а):П.с. поля datetime храняться в Y-m-d H:i:s. Я их не переделывал, так и вывожу...
Все. В чем профит... Во-первых integer, double, и т.д. сравниваются <, <=, >, >=, <>, =. Так же сравнивать можно и поля с datetime типом. Так же можно писать например: 2014 (все поля за 2014 год), <2014 (все поля до 2014 года) и т.д. Так же можно писать и <2014-02 (Все меньше февраля 2014) и т.д. по дням часам минутам...
Сильно строго не судите, критика принимается...
Критика уже была - юзабилити страдает.
Если уж совсем лень прикручивать ползунки - два инпута "от" и "до" - для пользователя и то лучше будет.
Дата так же от и до, но обязательно человеческими календарями. Если это сайт не для программистов - Ваши 2014-12-21 добрая половина пользователей просто не поймет, потому что так не принято писать даты в жизни.
Да, согласен что было бы удобней с человеческими датами... Но это надо будет переделывать работу с датой... Может потом займусь этим, сделаю все по человечески... А на счет ползунков... Ну даже не знаю... Мне кажется и так хорошо:)) Можно конечно тоже что-нибудь придумать... Доделаю как будет время... Спасибо...

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 20:50
Insolita
Shappy писал(а):

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

 if($this->owner->scenario != 'search')
            return;
Shappy писал(а): Как использовать:
1. В моделе добавляем сценарий search.
Сценарии нужные поисковые самому бы в behavior подставлять, причём чтоб массивом,а не один конкретно заданный

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 21:58
Shappy
Insolita писал(а):
Shappy писал(а):

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

 if($this->owner->scenario != 'search')
            return;
Shappy писал(а): Как использовать:
1. В моделе добавляем сценарий search.
Сценарии нужные поисковые самому бы в behavior подставлять, причём чтоб массивом,а не один конкретно заданный
Честно говоря не понял... Я понял так: чтобы behavior выполнялся только при определенных (нескольких) сценариях, которые укажет пользователь. Нам этот behavior нужен только при GridView, это всего один метод, больше он нигде не используется... Сделать это не проблема, а где это может понадобиться?

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 22:27
Insolita
ну вообще-то на одну модель может быть и несколько разных GridView и вариантов поисков

Re: GridView filter больше меньше <>=

Добавлено: 2014.11.26, 22:57
Shappy
Insolita писал(а):ну вообще-то на одну модель может быть и несколько разных GridView и вариантов поисков
Понял, спасибо, учту...