В общем... Сделал я 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 добавляем сценарий до валидации:
И с запросом работаем так:
Код: Выделить всё
$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) и т.д. по дням часам минутам...
Сильно строго не судите, критика принимается...