PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.7.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.7.0
2.11.0 2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 All 78 releases
fluent-community / vendor / wpfluent / framework / src / WPFluent / Database / Orm / Searchable.php

Searchable.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 2.7.0, at vendor/wpfluent/framework/src/WPFluent/Database/Orm/Searchable.php

161 lines 5.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCommunity\Framework\Database\Orm;
4
5 use Exception;
6 use FluentCommunity\Framework\Database\Schema;
7
8 trait Searchable
9 {
10 /**
11 * The property is intentionally NOT declared on the trait. Declaring it
12 * here with a default would make any model that redeclares it with its
13 * own columns (protected $searchableColumns = [...]) an incompatible
14 * trait composition and fatal in PHP. Models simply declare the property
15 * themselves; getSearchableColumns() reads it and defaults to an empty
16 * array when a model leaves it unset.
17 *
18 * @var array
19 */
20
21 /**
22 * Search the model in a case-insensitive manner.
23 *
24 * @param \FluentCommunity\Framework\Database\Orm\Builder $query
25 * @param string $value
26 * @return \FluentCommunity\Framework\Database\Orm\Builder
27 * @throws \Exception
28 */
29 public function scopeSearch($query, $value)
30 {
31 $columns = $this->ensureSearchableColumns();
32
33 $value = strtolower($value);
34
35 return $query->where(function($query) use ($columns, $value) {
36 foreach ($columns as $column) {
37 $query->orWhereRaw(
38 'LOWER(' . $column . ') LIKE ?', ['%' . $value . '%']
39 );
40 }
41 });
42 }
43
44 /**
45 * Search the searchable columns phonetically (SOUNDEX / "sounds like").
46 *
47 * @param \FluentCommunity\Framework\Database\Orm\Builder $query
48 * @param string $value
49 * @return \FluentCommunity\Framework\Database\Orm\Builder
50 * @throws \Exception
51 */
52 public function scopeSoundsLike($query, $value)
53 {
54 $columns = $this->ensureSearchableColumns();
55
56 return $query->where(function($query) use ($columns, $value) {
57 foreach ($columns as $column) {
58 $query->orWhereSoundsLike($column, $value);
59 }
60 });
61 }
62
63 /**
64 * Search the searchable columns by fuzzy edit-distance (Levenshtein).
65 *
66 * @param \FluentCommunity\Framework\Database\Orm\Builder $query
67 * @param string $value
68 * @param int $distance
69 * @return \FluentCommunity\Framework\Database\Orm\Builder
70 * @throws \Exception
71 */
72 public function scopeSimilar($query, $value, $distance = 2)
73 {
74 $columns = $this->ensureSearchableColumns();
75
76 return $query->where(function($query) use ($columns, $value, $distance) {
77 foreach ($columns as $column) {
78 $query->orWhereSimilar($column, $value, $distance);
79 }
80 });
81 }
82
83 /**
84 * Search the searchable columns by full-text relevance, returning rows
85 * ranked by how well they match (a "relevance" column is added).
86 *
87 * On MySQL/MariaDB this uses native FULLTEXT ranking and requires a
88 * FULLTEXT index on the searchable columns (see Schema::fullText()). When
89 * $fuzzy is true, recall is widened with a phonetic ("sounds like") match
90 * so misspellings still surface (below the ranked hits).
91 *
92 * SQLite has no native FULLTEXT, so it degrades to a case-insensitive
93 * LIKE match across the columns (unranked).
94 *
95 * @param \FluentCommunity\Framework\Database\Orm\Builder $query
96 * @param string $value
97 * @param bool $fuzzy
98 * @return \FluentCommunity\Framework\Database\Orm\Builder
99 * @throws \Exception
100 */
101 public function scopeRelevanceSearch($query, $value, $fuzzy = false)
102 {
103 $columns = $this->ensureSearchableColumns();
104
105 if (Schema::isSqlite()) {
106 return $query->where(function($query) use ($columns, $value, $fuzzy) {
107 foreach ($columns as $column) {
108 $query->orWhereLike($column, $value);
109
110 if ($fuzzy) {
111 $query->orWhereSoundsLike($column, $value);
112 }
113 }
114 });
115 }
116
117 return $query
118 ->selectRelevance($columns, $value)
119 ->where(function($query) use ($columns, $value, $fuzzy) {
120 $query->whereFullText($columns, $value);
121
122 if ($fuzzy) {
123 foreach ($columns as $column) {
124 $query->orWhereSoundsLike($column, $value);
125 }
126 }
127 })
128 ->orderByRelevance();
129 }
130
131 /**
132 * Get the model's searchable columns, defaulting to an empty array when
133 * the model does not declare the $searchableColumns property.
134 *
135 * @return array
136 */
137 protected function getSearchableColumns()
138 {
139 return $this->searchableColumns ?? [];
140 }
141
142 /**
143 * Ensure searchable columns are defined on the model and return them.
144 *
145 * @return array
146 * @throws \Exception
147 */
148 protected function ensureSearchableColumns()
149 {
150 $columns = $this->getSearchableColumns();
151
152 if (empty($columns)) {
153 throw new Exception(
154 'No searchable columns were defined in ' . get_class($this) . '.'
155 );
156 }
157
158 return $columns;
159 }
160 }
161