1 | <?php |
||||||
2 | /** |
||||||
3 | * @link https://github.com/Vintage-web-production/yii2-search |
||||||
4 | * @copyright Copyright (c) 2017 Vintage Web Production |
||||||
5 | * @license BSD 3-Clause License |
||||||
6 | */ |
||||||
7 | |||||||
8 | namespace vintage\search; |
||||||
9 | |||||||
10 | use vintage\search\interfaces\CustomSearchInterface; |
||||||
11 | use Yii; |
||||||
12 | use yii\base\Component; |
||||||
13 | use yii\base\InvalidConfigException; |
||||||
14 | use yii\base\Model; |
||||||
15 | use yii\db\BaseActiveRecord; |
||||||
16 | use yii\helpers\ArrayHelper; |
||||||
17 | use vintage\search\data\SearchResult; |
||||||
18 | use vintage\search\interfaces\SearchInterface; |
||||||
19 | |||||||
20 | /** |
||||||
21 | * Component for search in Active Record models. |
||||||
22 | * |
||||||
23 | * @author Vladimir Kuprienko <[email protected]> |
||||||
24 | * @since 1.0 |
||||||
25 | */ |
||||||
26 | class SearchComponent extends Component |
||||||
27 | { |
||||||
28 | /** |
||||||
29 | * @var array Array with configuration of models for search. |
||||||
30 | * @example |
||||||
31 | * ```php |
||||||
32 | * 'models' => [ |
||||||
33 | * 'articles' => [ |
||||||
34 | * 'class' => Article::class, |
||||||
35 | * 'label' => 'Articles', |
||||||
36 | * ], |
||||||
37 | * 'products' => [ |
||||||
38 | * 'class' => Product::class, |
||||||
39 | * 'label' => 'Shop products', |
||||||
40 | * ], |
||||||
41 | * // ... |
||||||
42 | * ] |
||||||
43 | * ``` |
||||||
44 | */ |
||||||
45 | public $models = []; |
||||||
46 | |||||||
47 | /** |
||||||
48 | * @var SearchResult[] Array of the search result. |
||||||
49 | */ |
||||||
50 | protected $result = []; |
||||||
51 | |||||||
52 | |||||||
53 | /** |
||||||
54 | * Method for searching. |
||||||
55 | * |
||||||
56 | * @example |
||||||
57 | * ```php |
||||||
58 | * $result = Yii::$app->get('searcher')->search('query for searching'); |
||||||
59 | * ``` |
||||||
60 | * |
||||||
61 | * @param string $query Keywords for search. |
||||||
62 | * @return SearchResult[] Array of the result objects. |
||||||
63 | * @throws \Exception |
||||||
64 | * @throws InvalidConfigException |
||||||
65 | */ |
||||||
66 | public function search($query) |
||||||
67 | { |
||||||
68 | foreach($this->models as $model) { |
||||||
69 | /* @var BaseActiveRecord|SearchInterface $searchModel */ |
||||||
70 | $searchModel = Yii::createObject($model['class']); |
||||||
71 | |||||||
72 | if(!$this->isSearchModel($searchModel)) { |
||||||
73 | throw new InvalidConfigException( |
||||||
74 | $model['class'] . 'should be instance of `\vintage\search\interfaces\SearchInterface` and `\yii\db\ActiveRecordInterface`' |
||||||
75 | ); |
||||||
76 | } |
||||||
77 | |||||||
78 | $activeQuery = $searchModel::find(); |
||||||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||||
79 | foreach($searchModel->getSearchFields() as $field) { |
||||||
80 | if(!$searchModel->hasAttribute($field)) { |
||||||
0 ignored issues
–
show
The method
hasAttribute() does not exist on vintage\search\interfaces\CustomSearchInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to vintage\search\interfaces\CustomSearchInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
The method
hasAttribute() does not exist on vintage\search\interfaces\SearchInterface . It seems like you code against a sub-type of said class. However, the method does not exist in vintage\search\interfaces\CustomSearchInterface . Are you sure you never get one of those?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
81 | throw new \Exception(sprintf("Field `%s` not found in `%s` model", $field, $model['class'])); |
||||||
82 | } |
||||||
83 | |||||||
84 | $activeQuery = ($searchModel instanceof CustomSearchInterface) |
||||||
85 | ? $searchModel->getQuery($activeQuery, $field, $query) |
||||||
86 | : $activeQuery->orWhere(['like', $field, $query]); |
||||||
87 | } |
||||||
88 | $this->addToResult($activeQuery->all()); |
||||||
89 | } |
||||||
90 | return $this->result; |
||||||
91 | } |
||||||
92 | |||||||
93 | /** |
||||||
94 | * Getting model label by model name. |
||||||
95 | * |
||||||
96 | * @param string $modelName |
||||||
97 | * @return null|string |
||||||
98 | */ |
||||||
99 | public function getModelLabel($modelName) |
||||||
100 | { |
||||||
101 | foreach($this->models as $model) { |
||||||
102 | if($model['class'] == $modelName) { |
||||||
103 | return $model['label']; |
||||||
104 | } |
||||||
105 | } |
||||||
106 | return null; |
||||||
107 | } |
||||||
108 | |||||||
109 | /** |
||||||
110 | * Method for adding iteration result to final result. |
||||||
111 | * |
||||||
112 | * @param \yii\db\ActiveRecord[] $foundModels |
||||||
113 | */ |
||||||
114 | protected function addToResult($foundModels) |
||||||
115 | { |
||||||
116 | if ($foundModels !== null) { |
||||||
117 | $tmp = SearchResult::buildMultiply($foundModels); |
||||||
118 | $this->result = ArrayHelper::merge($tmp, $this->result); |
||||||
119 | } |
||||||
120 | } |
||||||
121 | |||||||
122 | /** |
||||||
123 | * Check whether given model is search model. |
||||||
124 | * |
||||||
125 | * @param Model $model |
||||||
126 | * @return bool `true` if given model is search model. |
||||||
127 | * @since 1.1 |
||||||
128 | */ |
||||||
129 | protected function isSearchModel(Model $model) |
||||||
130 | { |
||||||
131 | return $model instanceof BaseActiveRecord |
||||||
132 | && $model instanceof SearchInterface; |
||||||
133 | } |
||||||
134 | } |
||||||
135 |