Skip to content

Commit 50d64d6

Browse files
chrispennyblueo
andauthored
v2: Remove Enterprise Search dependency. Silverstripe 6 support (#18)
* v2: Remove Enterprise Search dependency. Silverstripe 6 support * Updated interface implementation * update tests * Update to include synonym support * Update client * Fix for schema post * linting * Add extension to log detail for client errors (#23) * Add extension to log detail for client errors * add fallback for other exception types * update client version * update dependencies * update client dependency * Update composer description * Working through Fluent support changes * Update bifrost client to 0.0.6-alpha * Changes required for Fluent branch support (#24) * Changes required for Fluent branch support * Updates for IndexData changes * update dependency * update interface and add 2.0.x-dev alias --------- Co-authored-by: Bernie Hamlin <bernie@silverstripe.com> --------- Co-authored-by: Bernard Hamlin <948122+blueo@users.noreply.github.com> Co-authored-by: Bernie Hamlin <bernie@silverstripe.com>
1 parent d97cbcd commit 50d64d6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2188
-380
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77

88
jobs:
99
ci:
10-
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v1
10+
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v2
1111
with:
1212
# disable auto detection of JS tests (remove if any JS tests are added)
1313
js: false

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ This module **does not** provide any method for performing searches on your engi
99
* [Installation](#installation)
1010
* [Engine vs Index](#engine-vs-index)
1111
* [Specify environment variables](#specify-environment-variables)
12-
* [Understanding your engine prefix and suffix:](#understanding-your-engine-prefix-and-suffix)
12+
* [Understanding your engine prefix and engine suffix:](#understanding-your-engine-prefix-and-engine-suffix)
1313
* [Configuration](#configuration)
1414
* [File attachments for content extraction](#file-attachments-for-content-extraction)
1515
* [Additional documentation](#additional-documentation)
@@ -40,20 +40,20 @@ To integrate with Silverstripe Search, define environment variables containing y
4040

4141
```
4242
BIFROST_ENDPOINT="https://abc.provided.domain"
43-
BIFROST_ENGINE_PREFIX="<engine-prefix>" # See "Understanding your engine prefix and suffix" below
43+
BIFROST_ENGINE_PREFIX="<enginePrefix>" # See "Understanding your engine prefix and engine suffix" below
4444
BIFROST_MANAGEMENT_API_KEY="abc.123.xyz"
4545
```
4646

47-
### Understanding your engine prefix and suffix:
47+
### Understanding your engine prefix and engine suffix:
4848

4949
> [!IMPORTANT]
5050
> **TL;DR:**
51-
> - All Silverstripe Search engine names follow a 4 slug format like this: `search-<subscription>-<environment>-<suffix>`
52-
> - Your `<engine-prefix>` is everything except `-<suffix>`; so, it's just `search-<subscription>-<environment>`
51+
> - All Silverstripe Search engine names follow a 4 slug format like this: `search-<subscription>-<environment>-<engineSuffix>`
52+
> - Your `<enginePrefix>` is everything except `-<engineSuffix>`; so, it's just `search-<subscription>-<environment>`
5353
5454
For example:
5555

56-
| Engine | Engine prefix | Engine suffix |
56+
| Engine name | Engine prefix | Engine suffix |
5757
|---------------------------|----------------------|---------------|
5858
| search-acmecorp-prod-main | search-acmecorp-prod | main |
5959
| search-acmecorp-prod-inc | search-acmecorp-prod | inc |
@@ -64,7 +64,7 @@ For example:
6464

6565
Because you probably have more than one environment type that you're running search on (e.g. Production and UAT), and (generally speaking) you should have different engines for each of those environments. So, you can't just hardcode the entire engine name into your project, because that code doesn't change between environments.
6666

67-
Whenever you make a query, Forager will ask you for the "index" name; you will actually want to provide only the `<suffix>`. We will then take `BIFROST_ENGINE_PREFIX` and your `<suffix>`, put them together, and that's what will be queried. This allows you to set `BIFROST_ENGINE_PREFIX` differently for each environment, while having your `<suffix>` hardcoded in your project.
67+
Whenever you make a query, Forager will ask you for the "index" name; you will actually want to provide only the `<engineSuffix>`. We will then take `BIFROST_ENGINE_PREFIX` and your `<engineSuffix>`, put them together, and that's what will be queried. This allows you to set `BIFROST_ENGINE_PREFIX` differently for each environment, while having your `<engineSuffix>` hardcoded in your project.
6868

6969
## Configuration
7070

@@ -84,7 +84,7 @@ You can specify these data types in the `options` node of your fields.
8484
```yaml
8585
SilverStripe\Forager\Service\IndexConfiguration:
8686
indexes:
87-
<suffix>:
87+
<engineSuffix>:
8888
includeClasses:
8989
SilverStripe\CMS\Model\SiteTree:
9090
fields:
@@ -123,7 +123,7 @@ This field needs to contain a base 64 encoded string of binary for the file you
123123
```yaml
124124
SilverStripe\Forager\Service\IndexConfiguration:
125125
indexes:
126-
<suffix>:
126+
<engineSuffix>:
127127
includeClasses:
128128
SilverStripe\Assets\File:
129129
fields:

_config/config.yml

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,21 @@ Name: forager-bifrost
33
Only:
44
envvarset: 'BIFROST_MANAGEMENT_API_KEY'
55
After:
6-
- 'silverstripe-forager-elastic-enterprise'
76
- 'search-forager-default'
87
---
98
SilverStripe\Core\Injector\Injector:
109
SilverStripe\Forager\Service\IndexConfiguration:
1110
constructor:
12-
index_variant: '`BIFROST_ENGINE_PREFIX`'
11+
indexPrefix: '`BIFROST_ENGINE_PREFIX`'
1312
SilverStripe\Forager\Interfaces\IndexingInterface:
1413
class: SilverStripe\ForagerBifrost\Service\BifrostService
1514
constructor:
16-
client: '%$Elastic\EnterpriseSearch\Client.managementClient'
15+
client: '%$Silverstripe\Search\Client\Client.managementClient'
1716
configuration: '%$SilverStripe\Forager\Service\IndexConfiguration'
1817
builder: '%$SilverStripe\Forager\Service\DocumentBuilder'
19-
Elastic\EnterpriseSearch\Client.managementClient:
18+
Silverstripe\Search\Client\Client.managementClient:
2019
factory: SilverStripe\ForagerBifrost\Service\ClientFactory
2120
constructor:
2221
host: '`BIFROST_ENDPOINT`'
2322
token: '`BIFROST_MANAGEMENT_API_KEY`'
24-
http_client: '%$GuzzleHttp\Client'
25-
Elastic\EnterpriseSearch\AppSearch\Request\CreateEngine:
26-
class: SilverStripe\ForagerBifrost\Service\Requests\PostEngine
27-
Elastic\EnterpriseSearch\AppSearch\Request\DeleteDocuments:
28-
class: SilverStripe\ForagerBifrost\Service\Requests\DeleteDocuments
29-
Elastic\EnterpriseSearch\AppSearch\Request\GetSchema:
30-
class: SilverStripe\ForagerBifrost\Service\Requests\GetSchema
31-
Elastic\EnterpriseSearch\AppSearch\Request\IndexDocuments:
32-
class: SilverStripe\ForagerBifrost\Service\Requests\PostDocuments
33-
Elastic\EnterpriseSearch\AppSearch\Request\ListDocuments:
34-
class: SilverStripe\ForagerBifrost\Service\Requests\PostDocumentsList
35-
Elastic\EnterpriseSearch\AppSearch\Request\ListEngines:
36-
class: SilverStripe\ForagerBifrost\Service\Requests\PostEngines
37-
Elastic\EnterpriseSearch\AppSearch\Request\PutSchema:
38-
class: SilverStripe\ForagerBifrost\Service\Requests\PostSchema
39-
40-
SilverStripe\ForagerElasticEnterprise\Service\EnterpriseSearchService:
41-
# Append to existing valid_field_types definition
42-
valid_field_types:
43-
binary: 'binary'
44-
# Maximum search Document size: 25 MB
45-
max_document_size: 26214400
46-
47-
## customise the dataobject fields for Bifrost compatability
48-
SilverStripe\Forager\DataObject\DataObjectDocument:
49-
id_field: record_id
50-
base_class_field: record_base_class
51-
page_content_field: page_content
23+
httpClient: '%$GuzzleHttp\Client'

_config/dataobject.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
Name: forager-bifrost-dataobject
3+
Only:
4+
envvarset: 'BIFROST_MANAGEMENT_API_KEY'
5+
---
6+
# Customise the dataobject fields for Bifrost compatability
7+
SilverStripe\Forager\DataObject\DataObjectDocument:
8+
id_field: record_id
9+
base_class_field: record_base_class
10+
page_content_field: page_content

_config/extensions.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,12 @@ SilverStripe\Assets\File:
1010
SilverStripe\AssetAdmin\Forms\FileFormFactory:
1111
extensions:
1212
ForagerBifrostFileFormExtension: SilverStripe\ForagerBifrost\Extensions\FileFormExtension
13+
14+
---
15+
Name: 'forager-bifrost-extensions-queuedjobs'
16+
Only:
17+
moduleexists: 'symbiote/silverstripe-queuedjobs'
18+
---
19+
Symbiote\QueuedJobs\Services\QueuedJobService:
20+
extensions:
21+
ForagerBifrostQueuedJobsExtension: SilverStripe\ForagerBifrost\Extensions\QueuedJobsExtension

_config/synonyms.yml

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ Name: forager-bifrost-synonyms
33
Only:
44
envvarset: 'BIFROST_MANAGEMENT_API_KEY'
55
After:
6-
- 'silverstripe-forager-elastic-enterprise-synonyms'
76
- 'silverstripe-forager-synonyms'
87
---
98
SilverStripe\Core\Injector\Injector:
10-
# Adaptors provided by this module
119
SilverStripe\Forager\Interfaces\Requests\CreateSynonymRuleAdaptor:
1210
class: SilverStripe\ForagerBifrost\Adaptors\Requests\CreateSynonymRuleAdaptor
1311
SilverStripe\Forager\Interfaces\Requests\GetSynonymRuleAdaptor:
@@ -18,17 +16,5 @@ SilverStripe\Core\Injector\Injector:
1816
class: SilverStripe\ForagerBifrost\Adaptors\Requests\UpdateSynonymRuleAdaptor
1917
SilverStripe\Forager\Interfaces\Requests\DeleteSynonymRuleAdaptor:
2018
class: SilverStripe\ForagerBifrost\Adaptors\Requests\DeleteSynonymRuleAdaptor
21-
# Adaptors provided by the ElasticEnterprise dependency
2219
SilverStripe\Forager\Interfaces\Requests\GetSynonymCollectionsAdaptor:
23-
class: SilverStripe\ForagerElasticEnterprise\Adaptors\Requests\GetSynonymCollectionsAdaptor
24-
# Request overrides to work with the Bifröst API
25-
Elastic\EnterpriseSearch\AppSearch\Request\DeleteSynonymSet:
26-
class: SilverStripe\ForagerBifrost\Service\Requests\DeleteSynonymRule
27-
Elastic\EnterpriseSearch\AppSearch\Request\GetSynonymSet:
28-
class: SilverStripe\ForagerBifrost\Service\Requests\GetSynonymRule
29-
Elastic\EnterpriseSearch\AppSearch\Request\ListSynonymSets:
30-
class: SilverStripe\ForagerBifrost\Service\Requests\GetSynonymRules
31-
Elastic\EnterpriseSearch\AppSearch\Request\CreateSynonymSet:
32-
class: SilverStripe\ForagerBifrost\Service\Requests\CreateSynonymRule
33-
Elastic\EnterpriseSearch\AppSearch\Request\PutSynonymSet:
34-
class: SilverStripe\ForagerBifrost\Service\Requests\UpdateSynonymRule
20+
class: SilverStripe\ForagerBifrost\Adaptors\Requests\GetSynonymCollectionsAdaptor

composer.json

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "silverstripe/silverstripe-forager-bifrost",
3-
"description": "A Silverstripe Search add-on for silverstripe/silverstripe-forager",
3+
"description": "A Silverstripe Search adaptor for silverstripe/silverstripe-forager",
44
"type": "silverstripe-vendormodule",
55
"license": "BSD-3-Clause",
66
"homepage": "https://github.com/silverstripeltd/silverstripe-forager-bifrost",
@@ -17,26 +17,17 @@
1717
"Bifröst"
1818
],
1919
"require": {
20-
"php": "^8.1",
21-
"silverstripe/framework": "^5",
22-
"silverstripe/reports": "^5",
23-
"silverstripe/silverstripe-forager-elastic-enterprise": "^1.1",
24-
"guzzlehttp/guzzle": "^7"
20+
"php": "^8.3",
21+
"silverstripe/framework": "^6",
22+
"silverstripe/reports": "^6",
23+
"silverstripe/silverstripe-forager": "2.0.x-dev",
24+
"silverstripe/silverstripe-search-client-php": "0.0.7-alpha",
25+
"guzzlehttp/guzzle": "^7.9"
2526
},
2627
"require-dev": {
27-
"silverstripe/recipe-cms": "^5",
28-
"phpunit/phpunit": "^9.6.19",
29-
"slevomat/coding-standard": "^8.8"
30-
},
31-
"repositories": {
32-
"silverstripe/silverstripe-forager": {
33-
"type": "git",
34-
"url": "https://github.com/silverstripeltd/silverstripe-forager.git"
35-
},
36-
"silverstripe/silverstripe-forager-elastic-enterprise": {
37-
"type": "git",
38-
"url": "https://github.com/silverstripeltd/silverstripe-forager-elastic-enterprise.git"
39-
}
28+
"silverstripe/recipe-cms": "^6",
29+
"phpunit/phpunit": "^11.3",
30+
"slevomat/coding-standard": "~8.18.0"
4031
},
4132
"minimum-stability": "dev",
4233
"prefer-stable": true,
@@ -57,5 +48,10 @@
5748
},
5849
"scripts": {
5950
"phpcs": "phpcs --standard=phpcs.xml --extensions=php --encoding=utf-8"
51+
},
52+
"extra": {
53+
"branch-alias": {
54+
"dev-main": "2.0.x-dev"
55+
}
6056
}
6157
}

phpcs.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
<file>src</file>
66
<file>tests</file>
77

8+
<!-- Don't sniff test classes, because they include PHP attributes that cause Slevomat to throw errors -->
9+
<exclude-pattern>./tests/*</exclude-pattern>
810
<!-- Don't sniff third party libraries -->
911
<exclude-pattern>./vendor/*</exclude-pattern>
1012
<exclude-pattern>*/thirdparty/*</exclude-pattern>
@@ -146,6 +148,10 @@
146148
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification"/>
147149
<exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingTraversableTypeHintSpecification"/>
148150
<exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingTraversableTypeHintSpecification"/>
151+
<!-- Leave group order up to us -->
152+
<exclude name="SlevomatCodingStandard.Classes.ClassStructure.IncorrectGroupOrder"/>
153+
<!-- Leave the order up to us to decide -->
154+
<exclude name="SlevomatCodingStandard.Classes.ClassStructure.IncorrectGroupOrder"/>
149155
</rule>
150156

151157
<rule ref="SlevomatCodingStandard.Namespaces.UnusedUses">

phpunit.xml.dist

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55
<directory>tests</directory>
66
</testsuite>
77
</testsuites>
8-
<filter>
9-
<whitelist addUncoveredFilesFromWhitelist="true">
8+
<source>
9+
<include>
1010
<directory suffix=".php">src/</directory>
11-
<exclude>
12-
<directory suffix=".php">tests/</directory>
13-
</exclude>
14-
</whitelist>
15-
</filter>
11+
</include>
12+
<exclude>
13+
<directory suffix=".php">tests/</directory>
14+
</exclude>
15+
</source>
16+
<php>
17+
<env name="BIFROST_ENDPOINT" value="https://fakeplace.com" force="true"/>
18+
<env name="BIFROST_MANAGEMENT_API_KEY" value="fakeApiKey" force="true"/>
19+
</php>
1620
</phpunit>

src/Adaptors/Requests/CreateSynonymRuleAdaptor.php

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
namespace SilverStripe\ForagerBifrost\Adaptors\Requests;
44

5-
use Elastic\EnterpriseSearch\Client;
6-
use SilverStripe\Core\Injector\Injector;
75
use SilverStripe\Forager\Interfaces\Requests\CreateSynonymRuleAdaptor as PostSynonymRuleAdaptorInterface;
6+
use SilverStripe\Forager\Service\IndexConfiguration;
87
use SilverStripe\Forager\Service\Query\SynonymRule as SynonymRuleQuery;
98
use SilverStripe\Forager\Service\Results\SynonymRule as SynonymRuleResult;
109
use SilverStripe\ForagerBifrost\Processors\SynonymRuleProcessor;
11-
use SilverStripe\ForagerBifrost\Service\Requests\CreateSynonymRule;
10+
use Silverstripe\Search\Client\Client;
11+
use Silverstripe\Search\Client\Exception\SynonymRulePostNotFoundException;
12+
use Silverstripe\Search\Client\Exception\SynonymRulePostUnprocessableEntityException;
13+
use Silverstripe\Search\Client\Model\SynonymRuleRequest;
1214

1315
class CreateSynonymRuleAdaptor implements PostSynonymRuleAdaptorInterface
1416
{
@@ -24,16 +26,24 @@ public function setClient(?Client $client): void
2426
$this->client = $client;
2527
}
2628

29+
/**
30+
* @throws SynonymRulePostNotFoundException
31+
* @throws SynonymRulePostUnprocessableEntityException
32+
*/
2733
public function process(int|string $synonymCollectionId, SynonymRuleQuery $synonymRule): SynonymRuleResult
2834
{
29-
$request = Injector::inst()->create(CreateSynonymRule::class, $synonymCollectionId, $synonymRule);
35+
// Silverstripe Search simply uses the engine name as the Synonym Collection ID
36+
$engineName = IndexConfiguration::singleton()->environmentizeIndex($synonymCollectionId);
37+
// Convert the query into a Silverstripe Search synonym rule string
38+
$synonyms = SynonymRuleProcessor::getStringFromQuery($synonymRule);
39+
$request = new SynonymRuleRequest();
40+
$request->setSynonyms($synonyms);
3041

3142
// Should either be successful or throw an exception, which we'll let fly
32-
$body = $this->client->appSearch()->createSynonymSet($request)->asString();
33-
$body = json_decode($body, true);
43+
$response = $this->client->synonymRulePost($engineName, $request);
3444

35-
$synonymRuleResult = SynonymRuleResult::create($body['id']);
36-
SynonymRuleProcessor::applyStringToResult($synonymRuleResult, $body['synonyms']);
45+
$synonymRuleResult = SynonymRuleResult::create($response->getId());
46+
SynonymRuleProcessor::applyStringToResult($synonymRuleResult, $response->getSynonyms());
3747

3848
return $synonymRuleResult;
3949
}

0 commit comments

Comments
 (0)