algolia/algoliasearch-client-php
Official Algolia Search API client for PHP (8.0+). A thin, low-level HTTP SDK to index, update, and search records, manage indices, and interact with Algolia’s APIs. Install via Composer and start using SearchClient with your App ID and API key.
Installation:
composer require algolia/algoliasearch-client-php "^4.0"
Add to config/services.php (Laravel convention):
'algolia' => [
'app_id' => env('ALGOLIA_APP_ID'),
'api_key' => env('ALGOLIA_API_KEY'),
'index_prefix' => env('ALGOLIA_INDEX_PREFIX', ''),
],
Service Provider (Laravel):
// app/Providers/AlgoliaServiceProvider.php
use Algolia\AlgoliaSearch\SearchClient;
class AlgoliaServiceProvider extends ServiceProvider {
public function register() {
$this->app->singleton('algolia', function ($app) {
return SearchClient::create(
$app['config']['services.algolia.app_id'],
$app['config']['services.algolia.api_key']
);
});
}
}
First Use Case (Indexing):
// app/Services/AlgoliaService.php
class AlgoliaService {
protected $client;
public function __construct(SearchClient $client) {
$this->client = $client;
}
public function indexProduct(Product $product) {
$indexName = $this->getIndexName('products');
$this->client->saveObject($indexName, $product->toAlgoliaArray());
}
protected function getIndexName(string $type): string {
return config('services.algolia.index_prefix') . $type;
}
}
config('services.algolia')$response = $this->client->search([
'indexName' => 'products',
'query' => 'test',
]);
// Create index
$this->client->initIndex('products', [
'attributesForFaceting' => ['category', 'brand'],
]);
// Delete index
$this->client->deleteIndex('products');
// Partial update
$this->client->partialUpdateObject('products', '123', [
'price' => 99.99,
]);
// Batch save
$this->client->saveObjects('products', [
['objectID' => '1', 'name' => 'Product 1'],
['objectID' => '2', 'name' => 'Product 2'],
]);
$response = $this->client->search([
'indexName' => 'products',
'query' => 'laptop',
'attributesToRetrieve' => ['name', 'price', 'brand'],
'facets' => ['category', 'brand'],
'hitsPerPage' => 20,
'analytics' => true, // Track user behavior
'clickAnalytics' => true,
]);
// Start async task
$task = $this->client->saveObjects('products', $products);
// Wait for completion
$this->client->waitForTask('products', $task['taskID']);
// Poll status
$status = $this->client->getTaskStatus('products', $task['taskID']);
// Register with index prefix
$this->app->bind('algolia.index', function ($app, $indexName) {
$client = $app->make('algolia');
return $client->initIndex($indexName);
});
// Usage
$productsIndex = app('algolia.index', 'products');
// Listen to product created event
event(new ProductCreated($product));
// In listener
public function handle(ProductCreated $event) {
$this->algolia->indexProduct($event->product);
}
class AlgoliaQueryBuilder {
protected $client;
protected $index;
protected $query = [];
protected $options = [];
public function __construct(SearchClient $client, string $index) {
$this->client = $client;
$this->index = $index;
}
public function search(string $query): self {
$this->query['query'] = $query;
return $this;
}
public function withFacets(array $facets): self {
$this->options['facets'] = $facets;
return $this;
}
public function execute() {
return $this->client->search([
'indexName' => $this->index,
...$this->query,
...$this->options,
]);
}
}
// Usage
$query = (new AlgoliaQueryBuilder($client, 'products'))
->search('laptop')
->withFacets(['category', 'brand'])
->execute();
// app/Observers/ProductObserver.php
class ProductObserver {
protected $algolia;
public function __construct(AlgoliaService $algolia) {
$this->algolia = $algolia;
}
public function saved(Product $product) {
$this->algolia->indexProduct($product);
}
public function deleted(Product $product) {
$this->algolia->deleteProduct($product->id);
}
}
Algolia\AlgoliaSearch\Exceptions\ApiException with 429 statustry {
$response = $this->client->search(...);
} catch (ApiException $e) {
if ($e->getStatusCode() === 429) {
sleep($e->getRetryAfter());
retry();
}
throw $e;
}
Algolia\AlgoliaSearch\Exceptions\InvalidArgumentException for empty strings in required fields$objectID = trim($objectID) ?: uniqid();
waitForTask() hangs indefinitely$this->client->waitForTask('products', $taskID, 30); // 30 seconds
$indexName = config('app.env') . '_' . $baseIndexName;
$client = SearchClient::create(
$appId,
$apiKey,
['debug' => true] // Enable debug mode
);
// Override HttpClient to log requests
$client->getHttpClient()->setDebug(true);
condition in rules is deprecated (v4.39.1+)filter instead:
$rule = [
'condition' => ['anchor' => 'category', 'pattern' => 'electronics'],
// Use filter instead
'filter' => 'category == "electronics"',
];
// Process in chunks to avoid rate limits
$chunkSize = 1000;
foreach (array_chunk($products, $chunkSize) as $chunk) {
$this->client->saveObjects('products', $chunk);
sleep(1); // Respect rate limits
}
// Use Laravel's parallel processing
Parallel::for($products, 5, function ($product) {
$this->algolia->indexProduct($product);
});
// Cache search results (5 minutes)
$cacheKey = "algolia:products:{$query}";
$response = Cache::remember($cacheKey, now()->addMinutes(5), function () use ($query) {
return $this->client->search(['indexName' => 'products', 'query' => $query]);
});
// Use Guzzle with custom config
$client = SearchClient::create(
$appId,
$apiKey,
[
'httpClient' => new GuzzleHttp\Client([
'timeout' => 30,
'connect_timeout' => 10,
'headers' => [
'User-Agent' => 'MyApp/1.0',
],
]),
]
);
//
How can I help you explore Laravel packages today?