-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
442 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/.idea | ||
/bin | ||
/vendor | ||
/composer.lock | ||
/phpunit.xml | ||
/.phpunit.result.cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# Elastic AWS Client | ||
|
||
The official PHP Elasticsearch client for AWS Elasticsearch Service integrated with Laravel. | ||
|
||
## Contents | ||
|
||
* [Compatibility](#compatibility) | ||
* [Installation](#installation) | ||
* [Configuration](#configuration) | ||
* [Usage](#usage) | ||
|
||
## Compatibility | ||
|
||
The current version of Elastic AWS Client has been tested with the following configuration: | ||
|
||
* PHP 7.2-7.4 | ||
* Elasticsearch 7.x | ||
* AWS-SDK-PHP ^3.80 | ||
|
||
## Installation | ||
|
||
The library can be installed via Composer: | ||
|
||
```bash | ||
composer require tarfin-labs/elastic-aws-client | ||
``` | ||
|
||
## Configuration | ||
|
||
To change the client settings you need to publish the configuration file first: | ||
|
||
```bash | ||
php artisan vendor:publish --provider="ElasticAwsClient\ServiceProvider" | ||
``` | ||
|
||
You can use a bunch of settings supported by [\Elasticsearch\ClientBuilder::fromConfig](https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/configuration.html#_building_the_client_from_a_configuration_hash) | ||
method in the `config/elastic-aws-client.php` file as this factory is used under the hood: | ||
|
||
```php | ||
return [ | ||
'hosts' => [ | ||
[ | ||
'host' => env('ELASTICSEARCH_HOST', 'localhost'), | ||
'port' => env('ELASTICSEARCH_PORT', 9200), | ||
'scheme' => env('ELASTICSEARCH_SCHEME', null), | ||
'user' => env('ELASTICSEARCH_USER', null), | ||
'pass' => env('ELASTICSEARCH_PASS', null), | ||
|
||
// AWS | ||
'aws' => env('AWS_ELASTICSEARCH_ENABLED', false), | ||
'aws_region' => env('AWS_DEFAULT_REGION', ''), | ||
'aws_key' => env('AWS_ACCESS_KEY_ID', ''), | ||
'aws_secret' => env('AWS_SECRET_ACCESS_KEY', ''), | ||
'aws_credentials' => null | ||
], | ||
], | ||
'sslVerification' => null, | ||
'retries' => null, | ||
'sniffOnStart' => false, | ||
'httpHandler' => null, | ||
'connectionPool' => null, | ||
'connectionSelector' => null, | ||
'serializer' => null, | ||
'connectionFactory' => null, | ||
'endpoint' => null, | ||
'namespaces' => [], | ||
]; | ||
``` | ||
|
||
## Usage | ||
|
||
Type hint `\Elasticsearch\Client` or use `resolve` function to retrieve the client instance in your code: | ||
|
||
```php | ||
namespace App\Console\Commands; | ||
|
||
use Elasticsearch\Client; | ||
use Illuminate\Console\Command; | ||
|
||
class CreateIndex extends Command | ||
{ | ||
protected $signature = 'create:index {name}'; | ||
|
||
protected $description = 'Creates an index'; | ||
|
||
public function handle(Client $client) | ||
{ | ||
$client->indices()->create([ | ||
'index' => $this->argument('name') | ||
]); | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
{ | ||
"name": "tarfin-labs/elastic-aws-client", | ||
"description": "The official PHP Elasticsearch AWS client integrated with Laravel", | ||
"keywords": [ | ||
"laravel", | ||
"aws", | ||
"elastic", | ||
"elasticsearch", | ||
"client", | ||
"php" | ||
], | ||
"type": "library", | ||
"license": "MIT", | ||
"authors": [ | ||
{ | ||
"name": "Turan Karatuğ", | ||
"email": "[email protected]", | ||
"role": "Developer" | ||
}, | ||
{ | ||
"name": "Faruk Can", | ||
"email": "[email protected]", | ||
"role": "Developer" | ||
}, | ||
{ | ||
"name": "Yunus Emre Deligöz", | ||
"email": "[email protected]", | ||
"role": "Developer" | ||
}, | ||
{ | ||
"name": "Hakan Özdemir", | ||
"email": "[email protected]", | ||
"role": "Developer" | ||
} | ||
], | ||
"suggest": { | ||
"aws/aws-sdk-php": "Required to connect to an Elasticsearch host on AWS (^3.80)" | ||
}, | ||
"autoload": { | ||
"psr-4": { | ||
"ElasticAwsClient\\": "src" | ||
} | ||
}, | ||
"autoload-dev": { | ||
"psr-4": { | ||
"ElasticAwsClient\\Tests\\": "tests" | ||
} | ||
}, | ||
"require": { | ||
"php": "^7.2", | ||
"elasticsearch/elasticsearch": "^7.3" | ||
}, | ||
"require-dev": { | ||
"phpunit/phpunit": "^8.4", | ||
"orchestra/testbench": "^4.3" | ||
}, | ||
"config": { | ||
"bin-dir": "bin" | ||
}, | ||
"extra": { | ||
"laravel": { | ||
"providers": [ | ||
"ElasticAwsClient\\ServiceProvider" | ||
] | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?php | ||
|
||
return [ | ||
'hosts' => [ | ||
[ | ||
'host' => env('ELASTICSEARCH_HOST', 'localhost'), | ||
'port' => env('ELASTICSEARCH_PORT', 9200), | ||
'scheme' => env('ELASTICSEARCH_SCHEME', null), | ||
'user' => env('ELASTICSEARCH_USER', null), | ||
'pass' => env('ELASTICSEARCH_PASS', null), | ||
|
||
// AWS | ||
'aws' => env('AWS_ELASTICSEARCH_ENABLED', false), | ||
'aws_region' => env('AWS_DEFAULT_REGION', ''), | ||
'aws_key' => env('AWS_ACCESS_KEY_ID', ''), | ||
'aws_secret' => env('AWS_SECRET_ACCESS_KEY', ''), | ||
'aws_credentials' => null | ||
], | ||
], | ||
|
||
'sslVerification' => null, | ||
'retries' => null, | ||
'sniffOnStart' => false, | ||
'httpHandler' => null, | ||
'connectionPool' => null, | ||
'connectionSelector' => null, | ||
'serializer' => null, | ||
'connectionFactory' => null, | ||
'endpoint' => null, | ||
'namespaces' => [], | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.4/phpunit.xsd" | ||
bootstrap="vendor/autoload.php" | ||
executionOrder="depends,defects" | ||
forceCoversAnnotation="true" | ||
beStrictAboutCoversAnnotation="true" | ||
beStrictAboutOutputDuringTests="true" | ||
beStrictAboutTodoAnnotatedTests="true" | ||
verbose="true" | ||
colors="true"> | ||
<testsuites> | ||
<testsuite name="unit"> | ||
<directory suffix="Test.php">tests/Unit</directory> | ||
</testsuite> | ||
</testsuites> | ||
|
||
<filter> | ||
<whitelist processUncoveredFilesFromWhitelist="true"> | ||
<directory suffix=".php">src</directory> | ||
</whitelist> | ||
</filter> | ||
</phpunit> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
<?php | ||
|
||
namespace ElasticAwsClient; | ||
|
||
use Elasticsearch\Client; | ||
use Elasticsearch\ClientBuilder; | ||
use Illuminate\Support\Arr; | ||
use Psr\Log\LoggerInterface; | ||
use Monolog\Logger; | ||
use Monolog\Handler\StreamHandler; | ||
|
||
class Factory | ||
{ | ||
/** | ||
* Map configuration array keys with ES ClientBuilder setters | ||
* | ||
* @var array | ||
*/ | ||
protected $configMappings = [ | ||
'sslVerification' => 'setSSLVerification', | ||
'sniffOnStart' => 'setSniffOnStart', | ||
'retries' => 'setRetries', | ||
'httpHandler' => 'setHandler', | ||
'connectionPool' => 'setConnectionPool', | ||
'connectionSelector' => 'setSelector', | ||
'serializer' => 'setSerializer', | ||
'connectionFactory' => 'setConnectionFactory', | ||
'endpoint' => 'setEndpoint', | ||
'namespaces' => 'registerNamespace', | ||
]; | ||
|
||
/** | ||
* Make the Elasticsearch client for the given named configuration, or | ||
* the default client. | ||
* | ||
* @param array $config | ||
* | ||
* @return \Elasticsearch\Client|mixed | ||
*/ | ||
public function make(array $config) | ||
{ | ||
// Build the client | ||
return $this->buildClient($config); | ||
} | ||
|
||
/** | ||
* Build and configure an Elasticsearch client. | ||
* | ||
* @param array $config | ||
* | ||
* @return \Elasticsearch\Client | ||
*/ | ||
protected function buildClient(array $config): Client | ||
{ | ||
$clientBuilder = ClientBuilder::create(); | ||
|
||
// Configure hosts | ||
$clientBuilder->setHosts($config['hosts']); | ||
|
||
// Set additional client configuration | ||
foreach ($this->configMappings as $key => $method) { | ||
$value = Arr::get($config, $key); | ||
if (is_array($value)) { | ||
foreach ($value as $vItem) { | ||
$clientBuilder->$method($vItem); | ||
} | ||
} elseif ($value !== null) { | ||
$clientBuilder->$method($value); | ||
} | ||
} | ||
|
||
// Configure handlers for any AWS hosts | ||
foreach ($config['hosts'] as $host) { | ||
if (isset($host['aws']) && $host['aws']) { | ||
$clientBuilder->setHandler(function(array $request) use ($host) { | ||
$psr7Handler = \Aws\default_http_handler(); | ||
$signer = new \Aws\Signature\SignatureV4('es', $host['aws_region']); | ||
$request['headers']['Host'][0] = parse_url($request['headers']['Host'][0])['host']; | ||
|
||
// Create a PSR-7 request from the array passed to the handler | ||
$psr7Request = new \GuzzleHttp\Psr7\Request( | ||
$request['http_method'], | ||
(new \GuzzleHttp\Psr7\Uri($request['uri'])) | ||
->withScheme($request['scheme']) | ||
->withHost($request['headers']['Host'][0]), | ||
$request['headers'], | ||
$request['body'] | ||
); | ||
|
||
// Create the Credentials instance with the credentials from the environment | ||
$credentials = new \Aws\Credentials\Credentials($host['aws_key'], $host['aws_secret']); | ||
// check if the aws_credentials from config is set and if it contains a Credentials instance | ||
if (!empty($host['aws_credentials']) && $host['aws_credentials'] instanceof \Aws\Credentials\Credentials) { | ||
// Set the credentials as in config | ||
$credentials = $host['aws_credentials']; | ||
} | ||
|
||
if (!empty($host['aws_credentials']) && $host['aws_credentials'] instanceof \Closure) { | ||
// If it contains a closure you can obtain the credentials by invoking it | ||
$credentials = $host['aws_credentials']()->wait(); | ||
} | ||
|
||
// Sign the PSR-7 request | ||
$signedRequest = $signer->signRequest( | ||
$psr7Request, | ||
$credentials | ||
); | ||
|
||
// Send the signed request to Amazon ES | ||
/** @var \Psr\Http\Message\ResponseInterface $response */ | ||
$response = $psr7Handler($signedRequest) | ||
->then(function(\Psr\Http\Message\ResponseInterface $response) { | ||
return $response; | ||
}, function($error) { | ||
return $error['response']; | ||
}) | ||
->wait(); | ||
|
||
// Convert the PSR-7 response to a RingPHP response | ||
return new \GuzzleHttp\Ring\Future\CompletedFutureArray([ | ||
'status' => $response->getStatusCode(), | ||
'headers' => $response->getHeaders(), | ||
'body' => $response->getBody()->detach(), | ||
'transfer_stats' => ['total_time' => 0], | ||
'effective_url' => (string)$psr7Request->getUri(), | ||
]); | ||
}); | ||
} | ||
} | ||
|
||
// Build and return the client | ||
return $clientBuilder->build(); | ||
} | ||
} |
Oops, something went wrong.