typesense/typesense-php
Official PHP client for the Typesense search API. Install via Composer and use any HTTPlug-compatible HTTP client. Provides helpers like safe filter_by string escaping and supports modern Typesense server versions.
Installation:
composer require php-http/curl-client typesense/typesense-php
Ensure you have a supported HTTP client (e.g., php-http/curl-client or guzzlehttp/guzzle).
Initialize Client:
use Typesense\Client;
use Typesense\Connections\Connection;
use Typesense\Connections\TypesenseConnection;
$client = Client::create([
'nodes' => [
new TypesenseConnection('http://localhost:8108', 'your-api-key'),
],
'connection_timeout_seconds' => 2,
]);
First Use Case: Search in a collection:
$searchResults = $client->collections('products')
->documents()
->search('laptop', 10, ['query_by' => 'name,description']);
$client->collections('collection_name')$client->collections('collection_name')->documents()$collection->documents()->search($query, $per_page, $options)Define and update collection schemas:
$schema = [
'name' => 'products',
'fields' => [
['name' => 'name', 'type' => 'string'],
['name' => 'price', 'type' => 'float'],
],
'default_sorting_field' => 'name',
];
$client->collections()->create($schema);
// Create
$client->collections('products')->documents()->create([
'name' => 'MacBook Pro',
'price' => 1999.99,
]);
// Update
$client->collections('products')->documents()->update('doc_id', [
'price' => 1899.99,
]);
// Delete
$client->collections('products')->documents()->delete('doc_id');
$results = $client->collections('products')->documents()->search(
'laptop',
10,
[
'filter_by' => 'category:Laptops AND price<2000',
'query_by' => 'name,description',
'sort_by' => 'price:asc',
]
);
$results = $client->collections('products')->documents()->search(
'best laptop under $2000',
10,
[
'query_by' => 'name,description',
'search_by' => 'text',
'nls' => [
'model' => 'default',
'query' => 'best laptop under $2000',
],
]
);
$documents = [
['name' => 'Product 1', 'price' => 100],
['name' => 'Product 2', 'price' => 200],
];
$client->collections('products')->documents()->import($documents, ['batch_size' => 100]);
$client->collections()->createAlias('products', 'featured_products');
Laravel Service Provider:
Bind the client in AppServiceProvider for dependency injection:
$this->app->singleton(Client::class, function ($app) {
return Client::create([
'nodes' => [
new TypesenseConnection(config('typesense.url'), config('typesense.api_key')),
],
]);
});
Retry Logic:
The client automatically retries on 500/408 errors. Customize retry behavior via:
$client = Client::create([
'nodes' => [...],
'retry_config' => [
'max_retries' => 3,
'retry_on' => [500, 408, 429],
],
]);
Logging: Inject a custom logger (e.g., Monolog):
use Psr\Log\LoggerInterface;
$client = Client::create([
'nodes' => [...],
'logger' => $app->make(LoggerInterface::class),
]);
URL Encoding: The library automatically URL-encodes resource names (e.g., collection names, document IDs). Avoid manual encoding to prevent double-encoding issues.
Filter Syntax:
Use Typesense\FilterBy::escapeString() for dynamic filter values to handle special characters:
$filterValue = "O'Conner's book";
$filterBy = 'tags:=' . FilterBy::escapeString($filterValue);
Pagination:
Use per_page and offset for pagination, but note that offset can be inefficient for large datasets. Prefer search_after for deep pagination:
$results = $client->collections('products')->documents()->search(
'query',
10,
['search_after' => ['field1' => 'value1', 'field2' => 'value2']]
);
Schema Updates: Schema changes (e.g., adding fields) require a schema change operation to be applied. Use:
$client->collections('products')->schemaChanges()->create([
'add_fields' => [['name' => 'new_field', 'type' => 'string']],
]);
Connection Timeouts:
Default timeout is 2 seconds. Increase for unstable networks:
$client = Client::create([
'nodes' => [...],
'connection_timeout_seconds' => 5,
]);
HTTP Client Compatibility:
Ensure your HTTP client (e.g., Guzzle, cURL) is compatible with HTTPlug. Avoid unsupported clients like php-http/guzzle6-adapter for Guzzle 6.
Enable Debug Logging:
Set the debug option to log raw requests/responses:
$client = Client::create([
'nodes' => [...],
'debug' => true,
]);
Handle Invalid Responses:
The library throws Typesense\Exceptions\TypesenseException for API errors. Catch and inspect:
try {
$results = $client->collections('products')->documents()->search('query');
} catch (TypesenseException $e) {
\Log::error('Typesense error: ' . $e->getMessage());
\Log::error('Response: ' . $e->getResponse());
}
Validate Schema:
Use the validate method to check schema syntax before creation:
$client->collections()->validate($schema);
Custom HTTP Client:
Extend the client to use a custom HTTP client by implementing Http\Client\ClientInterface:
$client = Client::create([
'nodes' => [...],
'http_client' => $customHttpClient,
]);
Middleware: Add middleware to the HTTP client for request/response transformations:
$stack = Http\Discovery\MiddlewareStack::create();
$stack->push(Middleware\AddHeaders::class, ['X-Custom-Header' => 'value']);
$client = Client::create([
'nodes' => [...],
'http_client' => new \Http\Client\Curl\Client($stack),
]);
Event Listeners: Subscribe to schema change events or analytics events via the Typesense API and process them in Laravel events:
// Example: Listen to schema changes
$client->collections('products')->schemaChanges()->on('created', function ($event) {
\Log::info('Schema changed:', $event->getData());
});
Testing:
Use the Typesense\Mock\MockClient for unit tests:
$mockClient = new MockClient();
$mockClient->shouldReceive('search')->once()->andReturn(['hits' => []]);
How can I help you explore Laravel packages today?