123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341 |
- <?php
- namespace common\models\base;
- use yii\base\Model;
- use yii\data\ActiveDataProvider;
- use yii\data\Pagination;
- use yii\db\ActiveQuery;
- use yii\web\NotFoundHttpException;
- /**
- * // 示例一
- *
- * ```php
- * $searchModel = new SearchModel(
- * [
- * 'model' => Topic::class,
- * 'scenario' => 'default',
- * ]
- * );
- *
- * $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- *
- * return $this->render('index', [
- * 'dataProvider' => $dataProvider,
- * ]);
- * ```
- *
- * // 示例二
- *
- *```php
- * $searchModel = new SearchModel(
- * [
- * 'defaultOrder' => ['id' => SORT_DESC],
- * 'model' => Topic::class,
- * 'scenario' => 'default',
- * 'relations' => ['comment' => []], // 关联表(可以是Model里面的关联)
- * 'partialMatchAttributes' => ['title'], // 模糊查询
- * 'pageSize' => 15
- * ]
- * );
- *
- * $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- * $dataProvider->query->andWhere([Topic::tableName() . '.user_id' => 23, Comment::tableName() . '.status' => 1]);
- *
- * return $this->render('index', [
- * 'dataProvider' => $dataProvider,
- * ]);
- * ```
- *
- * Class SearchModel
- * @package common\components
- * @property \yii\db\ActiveRecord|\yii\base\Model $model
- */
- class SearchModel extends Model
- {
- private $attributes;
- private $attributeLabels;
- private $internalRelations;
- private $model;
- private $modelClassName;
- private $relationAttributes = [];
- private $rules;
- private $scenarios;
- /**
- * @var string 默认排序
- */
- public $defaultOrder;
- /**
- * @var string 分组
- */
- public $groupBy;
- /**
- * @var int 每页大小
- */
- public $pageSize = 10;
- /**
- * @var array 模糊查询
- */
- public $partialMatchAttributes = [];
- /**
- * @var array 区间查询
- */
- public $betweenMatchAttributes = [];
- /**
- * @var array
- */
- public $relations = [];
- /**
- * SearchModel constructor.
- * @param $params
- * @throws NotFoundHttpException
- */
- public function __construct($params)
- {
- $this->scenario = 'search';
- parent::__construct($params);
- if ($this->model === null) {
- throw new NotFoundHttpException('Param "model" cannot be empty');
- }
- $this->rules = $this->model->rules();
- $this->scenarios = $this->model->scenarios();
- $this->attributeLabels = $this->model->attributeLabels();
- foreach ($this->safeAttributes() as $attribute) {
- $this->attributes[$attribute] = '';
- }
- }
- /**
- * @param ActiveQuery $query
- * @param string $attribute
- * @param bool $partialMath
- */
- private function addCondition($query, $attribute, $partialMath = false)
- {
- if (isset($this->relationAttributes[$attribute])) {
- $attributeName = $this->relationAttributes[$attribute];
- } else {
- $attributeName = call_user_func([$this->modelClassName, 'tableName']) . '.' . $attribute;
- }
- $value = $this->$attribute;
- if ($value === '') {
- return;
- }
- if ($partialMath) {
- $query->andWhere(['like', $attributeName, trim($value)]);
- } elseif(in_array($attribute, $this->betweenMatchAttributes)) {
- $query->andWhere(['between', $attributeName, $value[0], $value[1]]);
- } else {
- $query->andWhere($this->conditionTrans($attributeName, $value));
- }
- }
- /**
- * 可以查询大于小于和IN
- *
- * @param $attributeName
- * @param $value
- * @return array
- */
- private function conditionTrans($attributeName, $value)
- {
- switch (true) {
- case is_array($value):
- return [$attributeName => $value];
- break;
- case stripos($value, '>=') !== false:
- return ['>=', $attributeName, substr($value, 2)];
- break;
- case stripos($value, '<=') !== false:
- return ['<=', $attributeName, substr($value, 2)];
- break;
- case stripos($value, '<') !== false:
- return ['<', $attributeName, substr($value, 1)];
- break;
- case stripos($value, '>') !== false:
- return ['>', $attributeName, substr($value, 1)];
- break;
- case stripos($value, ',') !== false:
- return [$attributeName => explode(',', $value)];
- break;
- default:
- return [$attributeName => $value];
- break;
- }
- }
- /**
- * @return Model
- */
- public function getModel()
- {
- return $this->model;
- }
- /**
- * @param mixed $value
- */
- public function setModel($value)
- {
- if ($value instanceof Model) {
- $this->model = $value;
- $this->scenario = $this->model->scenario;
- $this->modelClassName = get_class($value);
- } else {
- $this->model = new $value;
- $this->modelClassName = $value;
- }
- }
- /**
- * @return array
- */
- public function rules()
- {
- return $this->rules;
- }
- /**
- * @return array
- */
- public function attributeLabels()
- {
- return $this->attributeLabels;
- }
- /**
- * @return array
- */
- public function scenarios()
- {
- return $this->scenarios;
- }
- /**
- * @param array $params
- * @return ActiveDataProvider
- */
- public function search($params)
- {
- $query = call_user_func([$this->modelClassName, 'find']);
- $dataProvider = new ActiveDataProvider(
- [
- // 'query' => $query,
- // 'pagination' => [
- // 'pageSize' => $this->pageSize,
- // ]
- 'query' => $query,
- 'pagination' => new Pagination(
- [
- 'pageSize' => $this->pageSize,
- 'pageSizeParam'=>'limit',
- 'pageParam'=>'page'
- ]
- ),
- ]
- );
- if (is_array($this->relations)) {
- foreach ($this->relations as $relation => $attributes) {
- $pieces = explode('.', $relation);
- $path = '';
- $parentPath = '';
- foreach ($pieces as $i => $piece) {
- if ($i == 0) {
- $path = $piece;
- } else {
- $parentPath = $path;
- $path .= '.' . $piece;
- }
- if (!isset($this->internalRelations[$path])) {
- if ($i == 0) {
- $relationClass = call_user_func([$this->model, 'get' . $piece]);
- } else {
- $className = $this->internalRelations[$parentPath]['className'];
- $relationClass = call_user_func([new $className, 'get' . $piece]);
- }
- $this->internalRelations[$path] = [
- 'className' => $relationClass->modelClass,
- 'tableName' => call_user_func([$relationClass->modelClass, 'tableName']),
- ];
- }
- }
- foreach ((array)$attributes as $attribute) {
- // $attributeName = str_replace('.', '_', $relation) . '_' . $attribute;
- $attributeName = $relation . '.' . $attribute;
- $tableAttribute = $this->internalRelations[$relation]['tableName'] . '.' . $attribute;
- $this->rules[] = [$attributeName, 'safe'];
- $this->scenarios[$this->scenario][] = $attributeName;
- $this->attributes[$attributeName] = '';
- $this->relationAttributes[$attributeName] = $tableAttribute;
- $dataProvider->sort->attributes[$attributeName] = [
- 'asc' => [$tableAttribute => SORT_ASC],
- 'desc' => [$tableAttribute => SORT_DESC],
- ];
- }
- }
- $query->joinWith(array_keys($this->relations));
- }
- if (is_array($this->defaultOrder)) {
- $dataProvider->sort->defaultOrder = $this->defaultOrder;
- }
- if (is_array($this->groupBy)) {
- $query->addGroupBy($this->groupBy);
- }
- $this->load($params);
- foreach ($this->attributes as $name => $value) {
- $this->addCondition($query, $name, in_array($name, $this->partialMatchAttributes));
- }
- return $dataProvider;
- }
- /**
- * @param string $name
- * @return mixed
- * @throws \yii\base\UnknownPropertyException
- */
- public function __get($name)
- {
- if (isset($this->attributes[$name])) {
- return $this->attributes[$name];
- }
- return parent::__get($name);
- }
- /**
- * @param string $name
- * @param mixed $value
- * @throws \yii\base\UnknownPropertyException
- */
- public function __set($name, $value)
- {
- if (isset($this->attributes[$name])) {
- $this->attributes[$name] = $value;
- } else {
- parent::__set($name, $value);
- }
- }
- }
|