Skip to content

Commit 3cd896a

Browse files
3bd-ulrahmancrynobonetaylorotwell
authored
Supports for algolia/algoliasearch-client-php v4 (#872)
* update to algoliasearch-client-php v4 * Fixes tests Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * Apply suggestions from code review * Update EngineManager.php * Update composer.json * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * Update EngineManager.php * wip * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * wip Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> * Update AlgoliaEngine.php --------- Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com> Co-authored-by: Mior Muhammad Zaki <crynobone@gmail.com> Co-authored-by: Taylor Otwell <taylor@laravel.com>
1 parent b6a98ae commit 3cd896a

File tree

12 files changed

+770
-176
lines changed

12 files changed

+770
-176
lines changed

.github/workflows/tests.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ jobs:
1919
php: ['8.0', 8.1, 8.2, 8.3]
2020
laravel: [9, 10, 11]
2121
exclude:
22-
- php: '8.0'
23-
laravel: 9
2422
- php: '8.0'
2523
laravel: 10
2624
- php: '8.0'
@@ -47,8 +45,7 @@ jobs:
4745

4846
- name: Install dependencies
4947
run: |
50-
composer require "illuminate/contracts=^${{ matrix.laravel }}" --no-update
51-
composer update --prefer-dist --no-interaction --no-progress
48+
composer update --prefer-dist --no-interaction --no-progress --with="illuminate/contracts=^${{ matrix.laravel }}"
5249
5350
- name: Execute tests
5451
run: vendor/bin/phpunit
@@ -90,7 +87,8 @@ jobs:
9087
composer update --prefer-dist --no-interaction --no-progress
9188
9289
- name: Execute tests
93-
run: vendor/bin/phpunit --group external-network,meilisearch
90+
run: vendor/bin/phpunit --no-configuration --no-coverage --color --bootstrap vendor/autoload.php --group meilisearch tests/Integration
9491
env:
9592
MEILISEARCH_HOST: "http://localhost:7700"
9693
MEILISEARCH_KEY: 'masterKey'
94+
DB_CONNECTION: 'testing'

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"symfony/console": "^6.0|^7.0"
2626
},
2727
"require-dev": {
28-
"algolia/algoliasearch-client-php": "^3.2",
28+
"algolia/algoliasearch-client-php": "^3.2|^4.0",
2929
"typesense/typesense-php": "^4.9.3",
3030
"meilisearch/meilisearch-php": "^1.0",
3131
"mockery/mockery": "^1.0",
@@ -34,6 +34,9 @@
3434
"phpstan/phpstan": "^1.10",
3535
"phpunit/phpunit": "^9.3|^10.4"
3636
},
37+
"conflict": {
38+
"algolia/algoliasearch-client-php": "<3.2.0|>=5.0.0"
39+
},
3740
"autoload": {
3841
"psr-4": {
3942
"Laravel\\Scout\\": "src/"

phpstan.src.neon.dist

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,8 @@ parameters:
66
level: 0
77

88
ignoreErrors:
9+
- identifier: new.static
910
- "#\\(void\\) is used.#"
11+
12+
excludePaths:
13+
- src/Engines/Algolia3Engine.php

src/EngineManager.php

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
namespace Laravel\Scout;
44

5-
use Algolia\AlgoliaSearch\Config\SearchConfig;
6-
use Algolia\AlgoliaSearch\SearchClient as Algolia;
7-
use Algolia\AlgoliaSearch\Support\UserAgent;
5+
use Algolia\AlgoliaSearch\Algolia;
6+
use Algolia\AlgoliaSearch\Support\AlgoliaAgent as Algolia4UserAgent;
7+
use Algolia\AlgoliaSearch\Support\UserAgent as Algolia3UserAgent;
88
use Exception;
99
use Illuminate\Support\Manager;
10-
use Laravel\Scout\Engines\AlgoliaEngine;
10+
use Laravel\Scout\Engines\Algolia3Engine;
11+
use Laravel\Scout\Engines\Algolia4Engine;
1112
use Laravel\Scout\Engines\CollectionEngine;
1213
use Laravel\Scout\Engines\DatabaseEngine;
1314
use Laravel\Scout\Engines\MeilisearchEngine;
@@ -39,32 +40,41 @@ public function createAlgoliaDriver()
3940
{
4041
$this->ensureAlgoliaClientIsInstalled();
4142

42-
UserAgent::addCustomUserAgent('Laravel Scout', Scout::VERSION);
43-
44-
$config = SearchConfig::create(
45-
config('scout.algolia.id'),
46-
config('scout.algolia.secret')
47-
)->setDefaultHeaders(
48-
$this->defaultAlgoliaHeaders()
49-
);
50-
51-
if (is_int($connectTimeout = config('scout.algolia.connect_timeout'))) {
52-
$config->setConnectTimeout($connectTimeout);
53-
}
43+
return version_compare(Algolia::VERSION, '4.0.0', '>=')
44+
? $this->configureAlgolia4Driver()
45+
: $this->configureAlgolia3Driver();
46+
}
5447

55-
if (is_int($readTimeout = config('scout.algolia.read_timeout'))) {
56-
$config->setReadTimeout($readTimeout);
57-
}
48+
/**
49+
* Create an Algolia v3 engine instance.
50+
*
51+
* @return \Laravel\Scout\Engines\Algolia3Engine
52+
*/
53+
protected function configureAlgolia3Driver()
54+
{
55+
Algolia3UserAgent::addCustomUserAgent('Laravel Scout', Scout::VERSION); // @phpstan-ignore class.notFound
5856

59-
if (is_int($writeTimeout = config('scout.algolia.write_timeout'))) {
60-
$config->setWriteTimeout($writeTimeout);
61-
}
57+
return Algolia3Engine::make(
58+
config: config('scout.algolia'),
59+
headers: $this->defaultAlgoliaHeaders(),
60+
softDelete: config('scout.soft_delete')
61+
);
62+
}
6263

63-
if (is_int($batchSize = config('scout.algolia.batch_size'))) {
64-
$config->setBatchSize($batchSize);
65-
}
64+
/**
65+
* Create an Algolia v4 engine instance.
66+
*
67+
* @return \Laravel\Scout\Engines\Algolia4Engine
68+
*/
69+
protected function configureAlgolia4Driver()
70+
{
71+
Algolia4UserAgent::addAlgoliaAgent('Laravel Scout', 'Laravel Scout', Scout::VERSION);
6672

67-
return new AlgoliaEngine(Algolia::createWithConfig($config), config('scout.soft_delete'));
73+
return Algolia4Engine::make(
74+
config: config('scout.algolia'),
75+
headers: $this->defaultAlgoliaHeaders(),
76+
softDelete: config('scout.soft_delete')
77+
);
6878
}
6979

7080
/**
@@ -80,10 +90,6 @@ protected function ensureAlgoliaClientIsInstalled()
8090
return;
8191
}
8292

83-
if (class_exists('AlgoliaSearch\Client')) {
84-
throw new Exception('Please upgrade your Algolia client to version: ^3.2.');
85-
}
86-
8793
throw new Exception('Please install the suggested Algolia client: algolia/algoliasearch-client-php.');
8894
}
8995

src/Engines/Algolia3Engine.php

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
<?php
2+
3+
namespace Laravel\Scout\Engines;
4+
5+
use Algolia\AlgoliaSearch\Config\SearchConfig as Algolia3SearchConfig;
6+
use Algolia\AlgoliaSearch\SearchClient as Algolia3SearchClient;
7+
use Laravel\Scout\Builder;
8+
use Laravel\Scout\Jobs\RemoveableScoutCollection;
9+
10+
/**
11+
* @template TAlgoliaClient of \Algolia\AlgoliaSearch\SearchClient
12+
*/
13+
class Algolia3Engine extends AlgoliaEngine
14+
{
15+
/**
16+
* Create a new engine instance.
17+
*
18+
* @param TAlgoliaClient $algolia
19+
* @param bool $softDelete
20+
* @return void
21+
*/
22+
public function __construct(Algolia3SearchClient $algolia, $softDelete = false)
23+
{
24+
parent::__construct($algolia, $softDelete);
25+
}
26+
27+
/**
28+
* Make a new engine instance.
29+
*
30+
* @param array $config
31+
* @param array $headers
32+
* @param bool $softDelete
33+
* @return static
34+
*/
35+
public static function make(array $config, array $headers, bool $softDelete = false)
36+
{
37+
$config = Algolia3SearchConfig::create([
38+
'appId' => $config['id'],
39+
'apiKey' => $config['secret'],
40+
])->setDefaultHeaders($headers);
41+
42+
if (is_int($connectTimeout = $config['connect_timeout'])) {
43+
$configuration->setConnectTimeout($connectTimeout);
44+
}
45+
46+
if (is_int($readTimeout = $config['read_timeout'])) {
47+
$configuration->setReadTimeout($readTimeout);
48+
}
49+
50+
if (is_int($writeTimeout = $config['write_timeout'])) {
51+
$configuration->setWriteTimeout($writeTimeout);
52+
}
53+
54+
if (is_int($batchSize = $config['batch_size'])) {
55+
$configuration->setBatchSize($batchSize);
56+
}
57+
58+
return new static(Algolia3SearchClient::createWithConfig($configuration), $softDelete);
59+
}
60+
61+
/**
62+
* Update the given model in the index.
63+
*
64+
* @param \Illuminate\Database\Eloquent\Collection $models
65+
* @return void
66+
*
67+
* @throws \Algolia\AlgoliaSearch\Exceptions\AlgoliaException
68+
*/
69+
public function update($models)
70+
{
71+
if ($models->isEmpty()) {
72+
return;
73+
}
74+
75+
$index = $this->algolia->initIndex($models->first()->indexableAs());
76+
77+
if ($this->usesSoftDelete($models->first()) && $this->softDelete) {
78+
$models->each->pushSoftDeleteMetadata();
79+
}
80+
81+
$objects = $models->map(function ($model) {
82+
if (empty($searchableData = $model->toSearchableArray())) {
83+
return;
84+
}
85+
86+
return array_merge(
87+
$searchableData,
88+
$model->scoutMetadata(),
89+
['objectID' => $model->getScoutKey()],
90+
);
91+
})->filter()->values()->all();
92+
93+
if (! empty($objects)) {
94+
$index->saveObjects($objects);
95+
}
96+
}
97+
98+
/**
99+
* Remove the given model from the index.
100+
*
101+
* @param \Illuminate\Database\Eloquent\Collection $models
102+
* @return void
103+
*/
104+
public function delete($models)
105+
{
106+
if ($models->isEmpty()) {
107+
return;
108+
}
109+
110+
$index = $this->algolia->initIndex($models->first()->indexableAs());
111+
112+
$keys = $models instanceof RemoveableScoutCollection
113+
? $models->pluck($models->first()->getScoutKeyName())
114+
: $models->map->getScoutKey();
115+
116+
$index->deleteObjects($keys->all());
117+
}
118+
119+
/**
120+
* Delete a search index.
121+
*
122+
* @param string $name
123+
* @return mixed
124+
*/
125+
public function deleteIndex($name)
126+
{
127+
return $this->algolia->initIndex($name)->delete();
128+
}
129+
130+
/**
131+
* Flush all of the model's records from the engine.
132+
*
133+
* @param \Illuminate\Database\Eloquent\Model $model
134+
* @return void
135+
*/
136+
public function flush($model)
137+
{
138+
$index = $this->algolia->initIndex($model->indexableAs());
139+
140+
$index->clearObjects();
141+
}
142+
143+
/**
144+
* Perform the given search on the engine.
145+
*
146+
* @param \Laravel\Scout\Builder $builder
147+
* @param array $options
148+
* @return mixed
149+
*/
150+
protected function performSearch(Builder $builder, array $options = [])
151+
{
152+
$algolia = $this->algolia->initIndex(
153+
$builder->index ?: $builder->model->searchableAs()
154+
);
155+
156+
$options = array_merge($builder->options, $options);
157+
158+
if ($builder->callback) {
159+
return call_user_func(
160+
$builder->callback,
161+
$algolia,
162+
$builder->query,
163+
$options
164+
);
165+
}
166+
167+
return $algolia->search($builder->query, $options);
168+
}
169+
}

0 commit comments

Comments
 (0)