Completed
Push — master ( ce0ce3...9e2c54 )
by Vladimir
01:37
created

SearchComponent::isSearchModel()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
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 Yii;
11
use yii\base\Component;
12
use yii\base\InvalidConfigException;
13
use yii\base\Model;;
14
use yii\db\ActiveRecordInterface;
15
use yii\helpers\ArrayHelper;
16
use vintage\search\data\SearchResult;
17
use vintage\search\interfaces\SearchInterface;
18
19
/**
20
 * Component for search in Active Record models.
21
 *
22
 * @author Vladimir Kuprienko <[email protected]>
23
 * @since 1.0
24
 */
25
class SearchComponent extends Component
26
{
27
    /**
28
     * @var array Array with configuration of models for search.
29
     * @example
30
     * ```php
31
     * 'models' => [
32
     *      'articles' => [
33
     *          'class' => Article::class,
34
     *          'label' => 'Articles',
35
     *      ],
36
     *      'products' => [
37
     *          'class' => Product::class,
38
     *          'label' => 'Shop products',
39
     *      ],
40
     *      // ...
41
     * ]
42
     * ```
43
     */
44
    public $models = [];
45
46
    /**
47
     * @var string Current model class.
48
     */
49
    protected $_currentModel;
50
    /**
51
     * @var SearchResult[] Array of the search result.
52
     */
53
    protected $_result = [];
54
55
56
    /**
57
     * Method for searching.
58
     *
59
     * @example
60
     * ```php
61
     * $result = Yii::$app->get('searcher')->search('query for searching');
62
     * ```
63
     *
64
     * @param string $query Keywords for search.
65
     * @return SearchResult[] Array of the result objects.
66
     * @throws \Exception
67
     * @throws InvalidConfigException
68
     */
69
    public function search($query) {
70
        foreach($this->models as $model) {
71
            /* @var ActiveRecordInterface|SearchInterface|Model $searchModel */
72
            $searchModel = Yii::createObject($model['class']);
73
74
            if($this->isSearchModel($searchModel)) {
75
                $activeQuery = $searchModel::find();
0 ignored issues
show
Bug introduced by
The method find() does not exist on vintage\search\interfaces\SearchInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to vintage\search\interfaces\SearchInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

75
                /** @scrutinizer ignore-call */ 
76
                $activeQuery = $searchModel::find();
Loading history...
introduced by
The method find() does not exist on yii\base\Model. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

75
                /** @scrutinizer ignore-call */ 
76
                $activeQuery = $searchModel::find();
Loading history...
76
77
                foreach($searchModel->getSearchFields() as $field) {
78
                    if($searchModel->hasAttribute($field)) {
0 ignored issues
show
Bug introduced by
The method hasAttribute() does not exist on vintage\search\interfaces\SearchInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to vintage\search\interfaces\SearchInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

78
                    if($searchModel->/** @scrutinizer ignore-call */ hasAttribute($field)) {
Loading history...
79
                        $activeQuery->orWhere(['like', $field, $query]);
80
                    } else {
81
                        throw new \Exception(sprintf("Field `%s` not found in `%s` model", $field, $model['class']));
82
                    }
83
                }
84
85
                $foundModels = $activeQuery->all();
86
                if($foundModels !== null) {
87
                    $this->_currentModel = $searchModel;
0 ignored issues
show
Documentation Bug introduced by
It seems like $searchModel of type yii\db\ActiveRecordInterface or yii\base\Model or vintage\search\interfaces\SearchInterface is incompatible with the declared type string of property $_currentModel.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
88
                    $this->addToResult($foundModels);
89
                }
90
            } else {
91
                throw new InvalidConfigException(
92
                    $model['class'] . 'should be instance of `\vintage\search\interfaces\SearchInterface` and `\yii\db\ActiveRecordInterface`'
93
                );
94
            }
95
        }
96
97
        return $this->_result;
98
    }
99
100
    /**
101
     * Getting model label by model name.
102
     *
103
     * @param string $modelName
104
     * @return null|string
105
     */
106
    public function getModelLabel($modelName)
107
    {
108
        foreach($this->models as $model) {
109
            if($model['class'] == $modelName) {
110
                return $model['label'];
111
            }
112
        }
113
        return null;
114
    }
115
116
    /**
117
     * Method for adding iteration result to final result.
118
     *
119
     * @param \yii\db\ActiveRecord[] $foundModels
120
     */
121
    protected function addToResult($foundModels)
122
    {
123
        $tmp = SearchResult::buildMultiply($foundModels);
124
        $this->_result = ArrayHelper::merge($tmp, $this->_result);
125
    }
126
127
    /**
128
     * Check whether given model is search model.
129
     *
130
     * @param Model $model
131
     * @return bool `true` if given model is search model.
132
     * @since 1.1
133
     */
134
    protected function isSearchModel(Model $model)
135
    {
136
        return $model instanceof ActiveRecordInterface
137
            && $model instanceof SearchInterface;
138
    }
139
}
140