foolz/sphinxql-query-builder
## Getting Started
### First Steps
1. **Installation**: Add the package via Composer:
```bash
composer require foolz/sphinxql-query-builder
Ensure your PHP environment meets requirements (PHP 8.2+, mysqli or pdo_mysql).
Basic Connection Setup:
Choose either Mysqli or PDO driver:
// PDO Example
use Foolz\SphinxQL\Drivers\Pdo\Connection;
$conn = new Connection();
$conn->setParams([
'host' => '127.0.0.1',
'port' => 9306,
'charset' => 'utf8',
]);
First Query: Use the fluent builder for a simple search:
use Foolz\SphinxQL\SphinxQL;
$rows = (new SphinxQL($conn))
->select('id', 'title')
->from('articles')
->match('title', 'laravel')
->limit(10)
->execute()
->getStored();
SHOW TABLES, CALL commands).Fluent Query Building: Chain methods for readability and maintainability:
$query = (new SphinxQL($conn))
->select('user_id', 'score')
->from('search_results')
->where('status', '=', 'active')
->orderBy('score', 'DESC')
->limit(20);
Match Clauses with Callbacks:
Use MatchBuilder for complex full-text queries:
$query->match(function ($m) {
$m->field('title')->match('laravel')
->orMatch('php')
->withWeights([10, 5]);
});
Batch Processing: Execute multiple queries in a single round-trip:
$batch = (new SphinxQL($conn))
->select()->from('articles')->where('id', 1)->enqueue()
->select()->from('comments')->where('article_id', 1)->enqueue()
->executeBatch();
Faceted Search: Group results by attributes (e.g., categories):
$facet = (new Facet($conn))->facet(['category_id'])->orderBy('category_id', 'ASC');
$query->facet($facet);
Laravel Integration: Create a facade or service provider to wrap the builder:
// app/Providers/SphinxServiceProvider.php
public function register() {
$this->app->singleton('sphinx', function () {
$conn = new \Foolz\SphinxQL\Drivers\Pdo\Connection();
$conn->setParams(config('sphinx.connection'));
return new \Foolz\SphinxQL\SphinxQL($conn);
});
}
Use dependency injection in controllers:
public function search(Request $request, SphinxQL $sphinx) {
$results = $sphinx->select()->from('articles')
->match($request->query('q'))
->limit(10)
->execute()
->getStored();
}
Result Handling: Normalize results for API responses:
$results = $query->execute()->fetchAllAssoc();
return response()->json([
'data' => array_map(fn($row) => [
'id' => $row['id'],
'title' => $row['title'],
'score' => (float) $row['@weight'],
], $results),
]);
Error Handling: Wrap queries in try-catch blocks:
try {
$results = $query->execute()->getStored();
} catch (\Foolz\SphinxQL\Exception\QueryException $e) {
Log::error('SphinxQL Error: ' . $e->getMessage());
return response()->json(['error' => 'Search failed'], 500);
}
Connection Management:
Use Laravel's DatabaseManager pattern for connection pooling:
$conn = app('sphinx.connections')->connection('default');
Driver-Specific Quirks:
charset is set to avoid encoding issues (e.g., utf8mb4 for emoji support).MYSQLI_OPT_CONNECT_TIMEOUT to avoid hangs during connection drops.CALL PERCOLATE) are Manticore-specific. Check Helper::getCapabilities() before using.Result Format Inconsistencies:
@weight Field: SphinxQL returns scores in the @weight field by default. Explicitly select it if needed:
->select('id', '@weight as score')
executeBatch() returns an array where the first element is the primary query result, and subsequent elements are subqueries. Verify the order:
$batch = $query->executeBatch();
$mainResults = $batch->getStored()[0]; // Primary query
Facet Aggregation:
$facets = $batch->getStored()[1]; // Facet data
FACET syntax (v2.3+).Percolate Queries:
CALL PERCOLATE expects JSON strings for documents:
->documents(['{"subject":"test"}'])
tags() to filter percolate expressions:
->tags(['newsletter'])
Multi-Valued Attributes (MVA):
->value('tags', [1, 2, 3]) // Correct
->value('tags', '1,2,3') // Incorrect (string)
IN or ANY:
->where('tags', 'IN', [1, 2])
Compile Before Execute:
Use compile()->getCompiled() to inspect raw SQL:
$sql = $query->compile()->getCompiled();
Log::debug('Generated SQL:', ['sql' => $sql]);
Connection Issues:
netstat -tulnp | grep 9306).9306 by default).Performance:
EXPLAIN via the Helper to analyze query plans:
$helper->explain('SELECT * FROM rt WHERE MATCH(...)')->execute();
limit() or offset().Driver-Specific Logs:
$conn->setParams([
'pdo' => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
],
]);
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT) for detailed errors.SphinxQL class to add domain-specific methods:
class CustomSphinxQL extends \Foolz\SphinxQL\SphinxQL {
public function searchArticles(string $query, int $limit = 10) {
return $this->select('id', 'title', '@weight')
->from('articles')
->match(function ($m) use ($query) {
$m->field('title')->match($query)
->field('
How can I help you explore Laravel packages today?