SearchableTrait::toSearchableArray()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * @link https://github.com/vuongxuongminh/yii2-searchable
4
 * @copyright Copyright (c) 2019 Vuong Xuong Minh
5
 * @license [New BSD License](http://www.opensource.org/licenses/bsd-license.php)
6
 */
7
8
namespace vxm\searchable;
9
10
use Yii;
11
12
use yii\db\ActiveQueryInterface;
13
use yii\db\Exception;
14
15
use vxm\searchable\expression\Condition;
16
use vxm\searchable\expression\ConditionBuilder;
17
use vxm\searchable\expression\OrderBy;
18
use vxm\searchable\expression\OrderByBuilder;
19
20
/**
21
 * Trait SearchableTrait support implementing full-text search for the active record classes.
22
 *
23
 * @author Vuong Minh <[email protected]>
24
 * @since 1.0.0
25
 */
26
trait SearchableTrait
27
{
28
29
    /**
30
     * @inheritDoc
31
     * @return \yii\db\Connection
32
     */
33
    abstract public static function getDb();
34
35
    /**
36
     * @inheritDoc
37
     * @return string
38
     */
39
    abstract public static function tableName();
40
41
    /**
42
     * @inheritDoc
43
     * @return mixed
44
     */
45
    abstract public static function primaryKey();
46
47
    /**
48
     * @inheritDoc
49
     * @return \yii\db\ActiveQuery|\yii\db\ActiveQueryInterface
50
     */
51
    abstract public static function find();
52
53
    /**
54
     * Get searchable support full-text search for this model class.
55
     *
56
     * @return object|Searchable
57
     * @throws \yii\base\InvalidConfigException
58
     */
59 12
    public static function getSearchable(): Searchable
60
    {
61 12
        return Yii::$app->get('searchable');
62
    }
63
64
    /**
65
     * Creating active query had been apply search ids condition by given query string.
66
     *
67
     * @param string $query to search data.
68
     * @param string $mode using for query search, [[\vxm\searchable\Searchable::BOOLEAN_SEARCH]] or [[\vxm\searchable\Searchable::FUZZY_SEARCH]].
69
     * If not set [[\vxm\searchable\Searchable::$defaultSearchMode]] will be use.
70
     * @param array $config of [[\vxm\searchable\TNTSearch]].
71
     * @return \yii\db\ActiveQuery|ActiveQueryInterface query instance.
72
     * @throws \TeamTNT\TNTSearch\Exceptions\IndexNotFoundException
73
     * @throws \yii\base\InvalidConfigException
74
     */
75 6
    public static function search(string $query, ?string $mode = null, array $config = []): ActiveQueryInterface
76
    {
77 6
        $ids = static::searchIds($query, $mode, $config);
78
        /** @var \yii\db\ActiveQuery $aq */
79 6
        $aq = static::find();
80
81 6
        if (empty($ids)) {
82
83 3
            $aq->andWhere('1 = 0');
84
        } else {
85
            /** @var \yii\db\Connection $db */
86 4
            $db = static::getDb();
87 4
            $db->setQueryBuilder([
88 4
                'expressionBuilders' => [
89
                    Condition::class => ConditionBuilder::class,
90
                    OrderBy::class => OrderByBuilder::class
91
                ]
92
            ]);
93
            $expressionConfig = [
94 4
                'query' => $aq,
95 4
                'ids' => $ids
96
            ];
97 4
            $condition = new Condition($expressionConfig);
98 4
            $orderBy = new OrderBy($expressionConfig);
99 4
            $aq->andWhere($condition);
100 4
            $aq->addOrderBy($orderBy);
101
        }
102
103 6
        return $aq;
104
    }
105
106
    /**
107
     * Search ids by given query string.
108
     *
109
     * @param string $query to search data.
110
     * @param string|null $mode using for query search, [[\vxm\searchable\Searchable::BOOLEAN_SEARCH]] or [[\vxm\searchable\Searchable::FUZZY_SEARCH]].
111
     * If not set [[\vxm\searchable\Searchable::$defaultSearchMode]] will be use.
112
     * @param array $config of [[\vxm\searchable\TNTSearch]].
113
     * @return array search key values of indexing data search.
114
     * @throws \TeamTNT\TNTSearch\Exceptions\IndexNotFoundException
115
     * @throws \yii\base\InvalidConfigException
116
     */
117 8
    public static function searchIds(string $query, ?string $mode = null, array $config = []): array
118
    {
119 8
        $profileToken = "Searching data via query: `{$query}`";
120 8
        Yii::beginProfile($profileToken);
121
122
        try {
123 8
            $result = static::getSearchable()->search(static::class, $query, $mode, $config);
124
125 8
            return $result['ids'];
126
        } finally {
127
128 8
            Yii::endProfile($profileToken);
129
        }
130
    }
131
132
    /**
133
     * Delete all instances of the model from the search index.
134
     *
135
     * @throws \yii\base\InvalidConfigException
136
     */
137 5
    public static function deleteAllFromSearch(): void
138
    {
139 5
        static::getSearchable()->deleteAllFromSearch(static::class);
140 5
    }
141
142
    /**
143
     * Enable search syncing for this model class.
144
     */
145 2
    public static function enableSearchSyncing(): void
146
    {
147 2
        SearchableBehavior::enableSyncingFor(static::class);
148 2
    }
149
150
    /**
151
     * Disable search syncing for this model class.
152
     */
153 2
    public static function disableSearchSyncing(): void
154
    {
155 2
        SearchableBehavior::disableSyncingFor(static::class);
156 2
    }
157
158
    /**
159
     * Temporarily disable search syncing for the given callback.
160
     *
161
     * @param callable $callback will be call without syncing mode.
162
     * @return mixed value of $callback.
163
     */
164 2
    public static function withoutSyncingToSearch($callback)
165
    {
166 2
        static::disableSearchSyncing();
167
168
        try {
169 2
            return $callback();
170
        } finally {
171 2
            static::enableSearchSyncing();
172
        }
173
    }
174
175
    /**
176
     * Make given model searchable.
177
     *
178
     * @param \yii\db\ActiveRecord|\yii\db\ActiveRecord[]|static|static[] $models add to searchable index data.
179
     * @throws \TeamTNT\TNTSearch\Exceptions\IndexNotFoundException
180
     * @throws \yii\base\InvalidConfigException
181
     */
182 10
    public static function makeSearchable($models): void
183
    {
184 10
        static::getSearchable()->queueMakeSearchable($models);
0 ignored issues
show
Bug introduced by
It seems like $models defined by parameter $models on line 182 can also be of type array<integer,object<vxm...hable\SearchableTrait>> or object<vxm\searchable\SearchableTrait>; however, vxm\searchable\Searchable::queueMakeSearchable() does only seem to accept object<yii\db\ActiveReco...searchable\Searchable>>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
185 10
    }
186
187
    /**
188
     * Delete given model searchable.
189
     *
190
     * @param \yii\db\ActiveRecord|\yii\db\ActiveRecord[]|static|static[] $models delete from searchable index data.
191
     * @throws \TeamTNT\TNTSearch\Exceptions\IndexNotFoundException
192
     * @throws \yii\base\InvalidConfigException
193
     */
194 3
    public static function deleteSearchable($models): void
195
    {
196 3
        static::getSearchable()->queueDeleteFromSearch($models);
0 ignored issues
show
Bug introduced by
It seems like $models defined by parameter $models on line 194 can also be of type array<integer,object<vxm...hable\SearchableTrait>> or object<vxm\searchable\SearchableTrait>; however, vxm\searchable\Searchable::queueDeleteFromSearch() does only seem to accept object<yii\db\ActiveReco...searchable\Searchable>>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
197 3
    }
198
199
    /**
200
     * Make all instances of the model searchable.
201
     *
202
     * @throws \TeamTNT\TNTSearch\Exceptions\IndexNotFoundException
203
     * @throws \yii\base\InvalidConfigException
204
     */
205 7
    public static function makeAllSearchable(): void
206
    {
207 7
        foreach (static::find()->orderBy(static::searchableKey())->batch() as $models) {
208 7
            static::makeSearchable($models);
209
        }
210 7
    }
211
212
    /**
213
     * Get the index name for the model.
214
     *
215
     * @return string the name of an index.
216
     */
217 12
    public static function searchableIndex(): string
218
    {
219 12
        return static::getDb()->quoteSql(static::tableName());
220
    }
221
222
    /**
223
     * Get the indexable data array for the model.
224
     *
225
     * @return array ['field' => 'value'] or ['field alias' => 'value'].
226
     */
227 10
    public function toSearchableArray(): array
228
    {
229 10
        return $this->toArray();
0 ignored issues
show
Bug introduced by
It seems like toArray() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
230
    }
231
232
    /**
233
     * Get searchable key by default primary key will be use.
234
     *
235
     * @return string key name.
236
     */
237 11
    public static function searchableKey(): string
238
    {
239 11
        return current(static::primaryKey());
240
    }
241
242
    /**
243
     * Determine if the model should be searchable.
244
     *
245
     * @return bool weather instance should be insert to searchable index data.
246
     */
247
    public function shouldBeSearchable(): bool
248
    {
249
        return true;
250
    }
251
252
    /**
253
     * Make the given model instance searchable.
254
     *
255
     * @throws \TeamTNT\TNTSearch\Exceptions\IndexNotFoundException
256
     * @throws \yii\base\InvalidConfigException
257
     */
258 4
    public function searchable(): void
259
    {
260 4
        static::makeSearchable($this);
261 4
    }
262
263
    /**
264
     * Remove the given model instance from the search index.
265
     *
266
     * @throws \TeamTNT\TNTSearch\Exceptions\IndexNotFoundException
267
     * @throws \yii\base\InvalidConfigException
268
     */
269 3
    public function unsearchable(): void
270
    {
271 3
        static::deleteSearchable($this);
272 3
    }
273
274
    /**
275
     * Get searchable key value by default the primary key will be use.
276
     *
277
     * @param bool $asArray weather return an array have a key is a searchable key and value is an value of key or only value.
278
     * @return string|int|string[]|int[] value of an searchable key.
279
     * @throws Exception
280
     */
281 11
    public function getSearchableKey(bool $asArray = false)
282
    {
283 11
        $key = static::searchableKey();
284
285 11
        if ($asArray) {
286
            return [$key => $this->$key];
287
        } else {
288 11
            return $this->$key;
289
        }
290
    }
291
292
}
293