diff --git a/.gitignore b/.gitignore
index 8228c840..7e50fb64 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
.idea
.tmp
+.phpunit.result.cache
/composer.lock
+phpunit.xml
vendor
diff --git a/README.md b/README.md
index 03cd0ce0..e4da1ee1 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,14 @@ Run Typesense Server:
composer run-script typesenseServer
```
+Run tests:
+
+```shell script
+docker compose up
+cp phpunit.xml.dist phpunit.xml
+composer run-script test
+```
+
## Credits
This client was originally developed by [Abdullah Al-Faqeir](https://github.org/abdullahfaqeir) from
diff --git a/composer.json b/composer.json
index 757297e7..1f140e87 100644
--- a/composer.json
+++ b/composer.json
@@ -29,6 +29,11 @@
"Typesense\\": "src/"
}
},
+ "autoload-dev": {
+ "psr-4": {
+ "Tests\\": "tests/"
+ }
+ },
"require": {
"php": ">=7.4",
"ext-json": "*",
@@ -42,6 +47,7 @@
"psr/http-factory": "^1.0"
},
"require-dev": {
+ "phpunit/phpunit": "^11.2",
"squizlabs/php_codesniffer": "3.*",
"symfony/http-client": "^5.2"
},
@@ -57,6 +63,7 @@
"Composer\\Config::disableProcessTimeout",
"docker-compose up"
],
+ "test": "vendor/bin/phpunit",
"lint": "phpcs -v",
"lint:fix": "phpcbf"
}
diff --git a/examples/collection_operations.php b/examples/collection_operations.php
index 1068c312..21bf741c 100644
--- a/examples/collection_operations.php
+++ b/examples/collection_operations.php
@@ -194,7 +194,7 @@
echo "--------Delete Document-------\n";
echo "\n";
echo "--------Import Documents-------\n";
- $docsToImport = [];
+ $docsToImport = [];
$exportedDocStrsArray = explode('\n', $exportedDocStrs);
foreach ($exportedDocStrsArray as $exportedDocStr) {
$docsToImport[] = json_decode($exportedDocStr, true);
diff --git a/phpcs.xml b/phpcs.xml
index e7ff5dab..3b3ac751 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -5,6 +5,7 @@
src
examples
+ tests/
*/src/Standards/*/Tests/*\.(inc|css|js)$
*/tests/Core/*/*\.(inc|css|js)$
@@ -42,4 +43,4 @@
-
\ No newline at end of file
+
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 00000000..d79f0a2e
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,18 @@
+
+
+
+
+ tests/Feature
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Alias.php b/src/Alias.php
index 5dd76189..6f1e21d4 100644
--- a/src/Alias.php
+++ b/src/Alias.php
@@ -14,7 +14,6 @@
*/
class Alias
{
-
/**
* @var string
*/
diff --git a/src/Aliases.php b/src/Aliases.php
index d1c76cf1..70b9798a 100644
--- a/src/Aliases.php
+++ b/src/Aliases.php
@@ -14,7 +14,6 @@
*/
class Aliases implements \ArrayAccess
{
-
public const RESOURCE_PATH = '/aliases';
/**
diff --git a/src/AnalyticsRule.php b/src/AnalyticsRule.php
index bc8755f6..9ea6f3f5 100644
--- a/src/AnalyticsRule.php
+++ b/src/AnalyticsRule.php
@@ -10,7 +10,7 @@ class AnalyticsRule
public function __construct(string $ruleName, ApiCall $apiCall)
{
$this->ruleName = $ruleName;
- $this->apiCall = $apiCall;
+ $this->apiCall = $apiCall;
}
public function retrieve()
diff --git a/src/ApiCall.php b/src/ApiCall.php
index 563642c6..a114b592 100644
--- a/src/ApiCall.php
+++ b/src/ApiCall.php
@@ -29,7 +29,6 @@
*/
class ApiCall
{
-
private const API_KEY_HEADER_NAME = 'X-TYPESENSE-API-KEY';
/**
diff --git a/src/Client.php b/src/Client.php
index bde52c53..00d73858 100644
--- a/src/Client.php
+++ b/src/Client.php
@@ -92,7 +92,7 @@ public function __construct(array $config)
$this->apiCall = new ApiCall($this->config);
$this->collections = new Collections($this->apiCall);
- $this->stopwords = new Stopwords($this->apiCall);
+ $this->stopwords = new Stopwords($this->apiCall);
$this->aliases = new Aliases($this->apiCall);
$this->keys = new Keys($this->apiCall);
$this->debug = new Debug($this->apiCall);
diff --git a/src/Collections.php b/src/Collections.php
index 9385aa38..2a224ace 100644
--- a/src/Collections.php
+++ b/src/Collections.php
@@ -14,7 +14,6 @@
*/
class Collections implements \ArrayAccess
{
-
public const RESOURCE_PATH = '/collections';
/**
diff --git a/src/Document.php b/src/Document.php
index 617bf9ee..ba970f68 100644
--- a/src/Document.php
+++ b/src/Document.php
@@ -14,7 +14,6 @@
*/
class Document
{
-
/**
* @var string
*/
diff --git a/src/Documents.php b/src/Documents.php
index 641536d6..4c0c166c 100644
--- a/src/Documents.php
+++ b/src/Documents.php
@@ -14,7 +14,6 @@
*/
class Documents implements \ArrayAccess
{
-
public const RESOURCE_PATH = 'documents';
/**
diff --git a/src/Exceptions/ConfigError.php b/src/Exceptions/ConfigError.php
index b4fcc7cb..fa19f7b7 100644
--- a/src/Exceptions/ConfigError.php
+++ b/src/Exceptions/ConfigError.php
@@ -11,5 +11,4 @@
*/
class ConfigError extends TypesenseClientError
{
-
}
diff --git a/src/Exceptions/HTTPStatus0Error.php b/src/Exceptions/HTTPStatus0Error.php
index e2f2752c..ddd3b0ba 100644
--- a/src/Exceptions/HTTPStatus0Error.php
+++ b/src/Exceptions/HTTPStatus0Error.php
@@ -10,5 +10,4 @@
*/
class HTTPStatus0Error extends TypesenseClientError
{
-
}
diff --git a/src/Exceptions/ObjectAlreadyExists.php b/src/Exceptions/ObjectAlreadyExists.php
index 956cffd1..01bc7d2e 100644
--- a/src/Exceptions/ObjectAlreadyExists.php
+++ b/src/Exceptions/ObjectAlreadyExists.php
@@ -11,5 +11,4 @@
*/
class ObjectAlreadyExists extends TypesenseClientError
{
-
}
diff --git a/src/Exceptions/ObjectNotFound.php b/src/Exceptions/ObjectNotFound.php
index 7cae4b82..0b1d95bd 100644
--- a/src/Exceptions/ObjectNotFound.php
+++ b/src/Exceptions/ObjectNotFound.php
@@ -11,5 +11,4 @@
*/
class ObjectNotFound extends TypesenseClientError
{
-
}
diff --git a/src/Exceptions/ObjectUnprocessable.php b/src/Exceptions/ObjectUnprocessable.php
index 89a2f922..0a4b7972 100644
--- a/src/Exceptions/ObjectUnprocessable.php
+++ b/src/Exceptions/ObjectUnprocessable.php
@@ -11,5 +11,4 @@
*/
class ObjectUnprocessable extends TypesenseClientError
{
-
}
diff --git a/src/Exceptions/RequestMalformed.php b/src/Exceptions/RequestMalformed.php
index 2a7c42b7..5be3fe29 100644
--- a/src/Exceptions/RequestMalformed.php
+++ b/src/Exceptions/RequestMalformed.php
@@ -11,5 +11,4 @@
*/
class RequestMalformed extends TypesenseClientError
{
-
}
diff --git a/src/Exceptions/RequestUnauthorized.php b/src/Exceptions/RequestUnauthorized.php
index 47ec3533..bfa07a02 100644
--- a/src/Exceptions/RequestUnauthorized.php
+++ b/src/Exceptions/RequestUnauthorized.php
@@ -11,5 +11,4 @@
*/
class RequestUnauthorized extends TypesenseClientError
{
-
}
diff --git a/src/Exceptions/ServerError.php b/src/Exceptions/ServerError.php
index e13d18d0..5c1b3714 100644
--- a/src/Exceptions/ServerError.php
+++ b/src/Exceptions/ServerError.php
@@ -11,5 +11,4 @@
*/
class ServerError extends TypesenseClientError
{
-
}
diff --git a/src/Exceptions/ServiceUnavailable.php b/src/Exceptions/ServiceUnavailable.php
index 1b32bcb1..250e1e3f 100644
--- a/src/Exceptions/ServiceUnavailable.php
+++ b/src/Exceptions/ServiceUnavailable.php
@@ -11,5 +11,4 @@
*/
class ServiceUnavailable extends TypesenseClientError
{
-
}
diff --git a/src/Exceptions/Timeout.php b/src/Exceptions/Timeout.php
index 359eb338..7a2fc7bf 100644
--- a/src/Exceptions/Timeout.php
+++ b/src/Exceptions/Timeout.php
@@ -11,5 +11,4 @@
*/
class Timeout extends TypesenseClientError
{
-
}
diff --git a/src/Exceptions/TypesenseClientError.php b/src/Exceptions/TypesenseClientError.php
index 2f20c2a8..3011e1e1 100644
--- a/src/Exceptions/TypesenseClientError.php
+++ b/src/Exceptions/TypesenseClientError.php
@@ -13,7 +13,6 @@
*/
class TypesenseClientError extends Exception
{
-
public function setMessage(string $message): TypesenseClientError
{
$this->message = $message;
diff --git a/src/Key.php b/src/Key.php
index af7a9b1f..2539de16 100644
--- a/src/Key.php
+++ b/src/Key.php
@@ -14,7 +14,6 @@
*/
class Key
{
-
/**
* @var ApiCall
*/
diff --git a/src/Keys.php b/src/Keys.php
index 740d9098..fc7b0008 100644
--- a/src/Keys.php
+++ b/src/Keys.php
@@ -14,7 +14,6 @@
*/
class Keys implements \ArrayAccess
{
-
public const RESOURCE_PATH = '/keys';
/**
@@ -59,15 +58,16 @@ public function generateScopedSearchKey(
string $searchKey,
array $parameters
): string {
- $paramStr = json_encode($parameters, JSON_THROW_ON_ERROR);
- $digest = base64_encode(
+ $paramStr = json_encode($parameters, JSON_THROW_ON_ERROR);
+ $digest = base64_encode(
hash_hmac(
'sha256',
mb_convert_encoding($paramStr, 'UTF-8', 'ISO-8859-1'),
mb_convert_encoding($searchKey, 'UTF-8', 'ISO-8859-1'),
- true)
+ true
+ )
);
- $keyPrefix = substr($searchKey, 0, 4);
+ $keyPrefix = substr($searchKey, 0, 4);
$rawScopedKey = sprintf(
'%s%s%s',
mb_convert_encoding($digest, 'ISO-8859-1', 'UTF-8'),
diff --git a/src/Lib/Configuration.php b/src/Lib/Configuration.php
index 54f0e9ea..da53245c 100644
--- a/src/Lib/Configuration.php
+++ b/src/Lib/Configuration.php
@@ -20,7 +20,6 @@
*/
class Configuration
{
-
/**
* @var Node[]
*/
@@ -219,8 +218,8 @@ public function getClient(): ClientInterface
{
return new HttpMethodsClient(
$this->client ?? Psr18ClientDiscovery::find(),
- Psr17FactoryDiscovery::findRequestFactory(),
- Psr17FactoryDiscovery::findStreamFactory(),
+ Psr17FactoryDiscovery::findRequestFactory(),
+ Psr17FactoryDiscovery::findStreamFactory(),
);
}
}
diff --git a/src/Lib/Node.php b/src/Lib/Node.php
index 3500baae..1286ba5d 100644
--- a/src/Lib/Node.php
+++ b/src/Lib/Node.php
@@ -11,7 +11,6 @@
*/
class Node
{
-
/**
* @var string
*/
diff --git a/src/Override.php b/src/Override.php
index d50855fe..6061f5bb 100644
--- a/src/Override.php
+++ b/src/Override.php
@@ -14,7 +14,6 @@
*/
class Override
{
-
/**
* @var string
*/
diff --git a/src/Overrides.php b/src/Overrides.php
index a7cc48fa..46de7b6d 100644
--- a/src/Overrides.php
+++ b/src/Overrides.php
@@ -14,7 +14,6 @@
*/
class Overrides implements \ArrayAccess
{
-
public const RESOURCE_PATH = 'overrides';
/**
diff --git a/src/Presets.php b/src/Presets.php
index b0f56c01..29edc84c 100644
--- a/src/Presets.php
+++ b/src/Presets.php
@@ -63,7 +63,7 @@ public function get()
*/
public function put(array $options = [])
{
- $presetName = $options['preset_name'];
+ $presetName = $options['preset_name'];
$presetsData = $options['preset_data'];
return $this->apiCall->put($this->endpointPath($presetName), $presetsData);
diff --git a/src/Synonym.php b/src/Synonym.php
index 5ce46c15..0857423a 100644
--- a/src/Synonym.php
+++ b/src/Synonym.php
@@ -12,7 +12,6 @@
*/
class Synonym
{
-
/**
* @var string
*/
diff --git a/src/Synonyms.php b/src/Synonyms.php
index f48f2144..57c8d1a9 100644
--- a/src/Synonyms.php
+++ b/src/Synonyms.php
@@ -12,7 +12,6 @@
*/
class Synonyms implements \ArrayAccess
{
-
public const RESOURCE_PATH = 'synonyms';
/**
diff --git a/tests/Feature/CollectionTest.php b/tests/Feature/CollectionTest.php
new file mode 100644
index 00000000..2850d8e0
--- /dev/null
+++ b/tests/Feature/CollectionTest.php
@@ -0,0 +1,40 @@
+getSchema('books');
+
+ $response = $this->client()->collections->create($schema);
+
+ $this->assertEquals('books', $response['name']);
+ }
+
+ public function testCanRetrieveCollection(): void
+ {
+ $schema = $this->getSchema('books');
+ $this->client()->collections->create($schema);
+
+ $response = $this->client()->collections['books']->retrieve();
+
+ $this->assertEquals('books', $response['name']);
+ }
+
+ public function testCanDeleteCollection(): void
+ {
+ $schema = $this->getSchema('books');
+ $this->client()->collections->create($schema);
+
+ $this->client()->collections['books']->delete();
+
+ $this->expectException(ObjectNotFound::class);
+
+ $this->client()->collections['books']->retrieve();
+ }
+}
diff --git a/tests/Feature/DocumentsTest.php b/tests/Feature/DocumentsTest.php
new file mode 100644
index 00000000..eb78ba7f
--- /dev/null
+++ b/tests/Feature/DocumentsTest.php
@@ -0,0 +1,27 @@
+setUpCollection('books');
+ $this->setUpDocuments('books');
+ }
+
+ public function testCanUpdateDocumentsByFilter(): void
+ {
+ $document = ['publisher' => 'Renamed Publisher'];
+
+ $response = $this->client()->collections['books']->documents->update($document, [
+ 'filter_by' => 'publisher:=AwesomeBooks'
+ ]);
+
+ $this->assertGreaterThan(0, $response['num_updated']);
+ }
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644
index 00000000..61512692
--- /dev/null
+++ b/tests/TestCase.php
@@ -0,0 +1,88 @@
+setUpTypesenseClient();
+ }
+
+ protected function tearDown(): void
+ {
+ $this->tearDownTypesense();
+ }
+
+ protected function client(): Client
+ {
+ return $this->typesenseClient;
+ }
+
+ protected function getSchema(string $name): array
+ {
+ $path = __DIR__ . "/data/{$name}.schema.json";
+
+ return $this->loadFromDataDir($path);
+ }
+
+ protected function getData(string $name): array
+ {
+ $path = __DIR__ . "/data/{$name}.data.json";
+
+ return $this->loadFromDataDir($path);
+ }
+
+ private function loadFromDataDir(string $path): array
+ {
+ if (! file_exists($path)) {
+ return [];
+ }
+
+ return json_decode(
+ file_get_contents($path),
+ true,
+ 512,
+ JSON_THROW_ON_ERROR
+ );
+ }
+
+ private function setUpTypesenseClient(): void
+ {
+ $this->typesenseClient = new Client([
+ 'api_key' => $_ENV['TYPESENSE_API_KEY'],
+ 'nodes' => [
+ [
+ 'host' => $_ENV['TYPESENSE_NODE_HOST'],
+ 'port' => $_ENV['TYPESENSE_NODE_PORT'],
+ 'protocol' => $_ENV['TYPESENSE_NODE_PROTOCOL']
+ ],
+ ]
+ ]);
+ }
+
+ protected function setUpCollection(string $schema): void
+ {
+ $schema = $this->getSchema($schema);
+ $this->typesenseClient->collections->create($schema);
+ }
+
+ protected function setUpDocuments(string $schema): void
+ {
+ $documents = $this->getData($schema);
+ $this->typesenseClient->collections[$schema]->documents->import($documents);
+ }
+
+ private function tearDownTypesense(): void
+ {
+ $collections = $this->typesenseClient->collections->retrieve();
+ foreach ($collections as $collection) {
+ $this->typesenseClient->collections[$collection['name']]->delete();
+ }
+ }
+}
diff --git a/tests/data/books.data.json b/tests/data/books.data.json
new file mode 100644
index 00000000..1ec5615d
--- /dev/null
+++ b/tests/data/books.data.json
@@ -0,0 +1,34 @@
+[
+ {
+ "title": "Book 1",
+ "description": "Wonderful Description",
+ "authors": [
+ "Jane",
+ "John"
+ ],
+ "isbn": "1234567890",
+ "publisher": "AwesomeBooks",
+ "pages": 123
+ },
+ {
+ "title": "Book 2",
+ "description": "Another helpful description",
+ "authors": [
+ "Jeff",
+ "Mia"
+ ],
+ "isbn": "1234567891",
+ "publisher": "AwesomeBooks",
+ "pages": 150
+ },
+ {
+ "title": "Book 3",
+ "description": "Another useless description",
+ "authors": [
+ "Martin"
+ ],
+ "isbn": "1234567892",
+ "publisher": "PubLishEr",
+ "pages": 268
+ }
+]
diff --git a/tests/data/books.schema.json b/tests/data/books.schema.json
new file mode 100644
index 00000000..84f636ec
--- /dev/null
+++ b/tests/data/books.schema.json
@@ -0,0 +1,30 @@
+{
+ "name": "books",
+ "fields": [
+ {
+ "name": "title",
+ "type": "string"
+ },
+ {
+ "name": "description",
+ "type": "string"
+ },
+ {
+ "name": "authors",
+ "type": "string[]",
+ "facet": true
+ },
+ {
+ "name": "isbn",
+ "type": "string"
+ },
+ {
+ "name": "publisher",
+ "type": "string"
+ },
+ {
+ "name": "pages",
+ "type": "int32"
+ }
+ ]
+}