-
Notifications
You must be signed in to change notification settings - Fork 49
Expand file tree
/
Copy path11-fulltext-search.php
More file actions
203 lines (165 loc) · 6.32 KB
/
11-fulltext-search.php
File metadata and controls
203 lines (165 loc) · 6.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
<?php
/**
* Full-Text Search Examples
*
* Demonstrates full-text search functionality across MySQL, MariaDB, PostgreSQL, SQLite, MSSQL, and Oracle
*/
require_once __DIR__ . '/../../vendor/autoload.php';
require_once __DIR__ . '/../helpers.php';
use tommyknocker\pdodb\helpers\Db;
$db = createExampleDb();
$driver = getCurrentDriver($db);
echo "=== Full-Text Search Examples ($driver) ===\n\n";
// Create a table for testing full-text search
echo "Setting up test table with full-text index...\n";
// Create table using fluent API (cross-dialect)
$schema = $db->schema();
try {
$schema->dropTableIfExists('articles');
// Create table with fluent API
$schema->createTable('articles', [
'id' => $schema->primaryKey(),
'title' => $schema->string(255),
'content' => $schema->text(),
]);
// Create full-text index for MySQL/MariaDB
if (in_array($driver, ['mysql', 'mariadb'])) {
$db->rawQuery("ALTER TABLE articles ADD FULLTEXT INDEX ft_idx (title, content)");
}
// Create full-text index for PostgreSQL
if ($driver === 'pgsql') {
$db->rawQuery("ALTER TABLE articles ADD COLUMN ts_vector TSVECTOR GENERATED ALWAYS AS (to_tsvector('english', title || ' ' || content)) STORED");
$db->rawQuery("CREATE INDEX articles_ts_vector_idx ON articles USING GIN(ts_vector)");
}
// Create full-text index for SQLite (FTS5 virtual table)
if ($driver === 'sqlite') {
$schema->dropTable('articles');
$db->rawQuery("CREATE VIRTUAL TABLE articles USING fts5(title, content)");
}
// Create full-text index for Oracle (Oracle Text - requires CTXSYS.CONTEXT)
if ($driver === 'oci') {
try {
// Oracle Text requires CONTEXT index
// Note: This requires Oracle Text option to be installed
$db->rawQuery("CREATE INDEX articles_ft_idx ON articles (title, content) INDEXTYPE IS CTXSYS.CONTEXT");
} catch (\Exception $e) {
// If Oracle Text is not available, continue without index
// The example will use LIKE fallback
echo "Note: Oracle Text index not created. Full-text search will use LIKE fallback.\n";
}
}
echo "✓ Table created\n\n";
} catch (\Exception $e) {
echo "Note: Full-text indexes may require special setup\n";
echo "Error: " . $e->getMessage() . "\n";
// Create simple table without full-text index for demonstration
$schema->dropTableIfExists('articles');
recreateTable($db, 'articles', [
'id' => $schema->primaryKey(),
'title' => $schema->string(255),
'content' => $schema->text(),
]);
}
// Insert test data
echo "Inserting test data...\n";
$db->find()->table('articles')->insertMulti([
['title' => 'PHP Database Tutorial', 'content' => 'Learn how to use PHP with databases'],
['title' => 'MySQL Performance Guide', 'content' => 'Optimize your MySQL queries for better performance'],
['title' => 'PostgreSQL Best Practices', 'content' => 'Best practices for working with PostgreSQL'],
['title' => 'SQLite Mobile Apps', 'content' => 'Building mobile apps with SQLite database'],
['title' => 'Database Security', 'content' => 'Secure your database connections and prevent SQL injection'],
]);
echo "✓ Inserted 5 articles\n\n";
// Example 1: Basic full-text search
echo "=== 1. Basic Full-Text Search ===\n";
try {
$results = $db->find()
->from('articles')
->where(Db::match('title, content', 'database'))
->get();
echo "Results for search 'database': " . count($results) . "\n";
foreach ($results as $row) {
echo "- {$row['title']}\n";
}
} catch (Exception $e) {
echo "Note: Full-text search not configured. Error: " . $e->getMessage() . "\n";
}
echo "\n";
// Example 2: Full-text search with LIKE as fallback
echo "=== 2. Full-Text Search (fallback to LIKE) ===\n";
$searchTerm = 'performance';
$results = $db->find()
->from('articles')
->where(Db::like('title', "%{$searchTerm}%"))
->orWhere(Db::like('content', "%{$searchTerm}%"))
->get();
echo "Results for search '$searchTerm': " . count($results) . "\n";
foreach ($results as $row) {
echo "- {$row['title']}\n";
}
echo "\n";
// Example 3: Full-text search with LIKE (FulltextMatchValue only works with real FTS indexes)
echo "=== 3. Full-Text Search with LIKE ===\n";
$searchTerm = 'PHP';
$results = $db->find()
->from('articles')
->select(['id', 'title'])
->where(Db::like('title', "%{$searchTerm}%"))
->orWhere(Db::like('content', "%{$searchTerm}%"))
->orderBy('title', 'DESC')
->get();
echo "Results for search '$searchTerm':\n";
foreach ($results as $row) {
echo "- {$row['title']}\n";
}
echo "\n";
// Example 4: Multiple columns search
echo "=== 4. Multiple Columns Search ===\n";
$searchTerm = 'guide';
$results = $db->find()
->from('articles')
->where(Db::like('title', "%{$searchTerm}%"))
->orWhere(Db::like('content', "%{$searchTerm}%"))
->limit(10)
->get();
echo "Results for search '$searchTerm': " . count($results) . "\n";
foreach ($results as $row) {
echo "- {$row['title']}\n";
}
echo "\n";
// Example 5: Case-insensitive search
echo "=== 5. Case-Insensitive Search ===\n";
$searchTerm = 'sql';
$results = $db->find()
->from('articles')
->where(Db::ilike('title', "%{$searchTerm}%"))
->orWhere(Db::ilike('content', "%{$searchTerm}%"))
->get();
echo "Results for search '$searchTerm' (case-insensitive): " . count($results) . "\n";
foreach ($results as $row) {
echo "- {$row['title']}\n";
}
echo "\n";
echo "=== Schema Introspection Examples ===\n";
// Get table structure
echo "1. Table Structure:\n";
$structure = $db->describe('articles');
foreach ($structure as $col) {
$name = $col['Field'] ?? $col['column_name'] ?? $col['name'] ?? 'unknown';
$type = $col['Type'] ?? $col['data_type'] ?? $col['type'] ?? 'unknown';
echo "- $name: $type\n";
}
echo "\n";
// Get indexes
echo "2. Indexes:\n";
try {
$indexes = $db->find()->from('articles')->indexes();
foreach ($indexes as $index) {
$name = $index['Key_name'] ?? $index['index_name'] ?? $index['name'] ?? 'unknown';
echo "- Index: $name\n";
}
} catch (Exception $e) {
echo "- Could not retrieve indexes: " . $e->getMessage() . "\n";
}
echo "\n";
echo "=== All Full-Text Search Examples Completed ===\n";