diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml new file mode 100644 index 0000000..e2715bc --- /dev/null +++ b/.github/workflows/phpunit.yml @@ -0,0 +1,73 @@ +name: PHPUnit +on: + push: + branches: + - master + tags: + - "*.*.*" + pull_request: + branches: + - master + +jobs: + Build: + runs-on: 'ubuntu-latest' + container: 'byjg/php:${{ matrix.php-version }}-cli' + strategy: + matrix: + php-version: + - "8.2" + - "8.1" + - "8.0" + - "7.4" + + services: + mongodb: + image: mongo:3 + env: + TZ: America/Winnipeg + ports: + - 27017:27017 + + dynamodb: + image: amazon/dynamodb-local + ports: + - 8000:8000 + + s3: + image: localstack/localstack + ports: + - "4566:4566" + env: + SERVICES: s3 + DEFAULT_REGION: us-west-1 + AWS_DEFAULT_REGION: us-west-1 + HOSTNAME: s3 + HOSTNAME_EXTERNAL: s3 + USE_SSL: false + DEBUG: 1 + options: >- + --health-cmd "awslocal s3 ls" + --health-interval 5s + --health-timeout 10s + --health-retries 5 + + env: + MONGODB_CONNECTION: "mongodb://mongodb/test" + S3_CONNECTION: "s3://aaa:12345678@us-east-1/mybucket?create=true&endpoint=http://s3:4566" + DYNAMODB_CONNECTION: "dynamodb://aaa:123456@us-east-1/tablename?endpoint=http://dynamodb:8000" + + steps: + - uses: actions/checkout@v4 + - run: composer install + - run: ./vendor/bin/phpunit + + Documentation: + if: github.ref == 'refs/heads/master' + needs: Build + uses: byjg/byjg.github.io/.github/workflows/add-doc.yaml@master + with: + folder: php + project: ${{ github.event.repository.name }} + secrets: inherit + diff --git a/.gitignore b/.gitignore index d9a7098..f383a72 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ vendor .idea node_modules -.usdocker \ No newline at end of file +.usdocker +/.phpunit.result.cache diff --git a/.run/Test Project.run.xml b/.run/Test Project.run.xml index 6f7fb36..b096ea2 100644 --- a/.run/Test Project.run.xml +++ b/.run/Test Project.run.xml @@ -2,9 +2,9 @@ - + - + diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 81e8c45..0000000 --- a/.travis.yml +++ /dev/null @@ -1,37 +0,0 @@ -language: php -php: - - "7.3" - - "7.2" - - "7.1" - - "7.0" - - "5.6" - - -addons: - hosts: - - mongodb-container - -services: - - docker - -before_install: - - docker-compose up -d - - echo "extension = mongodb.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - - export MONGODB_CONNECTION="mongodb://127.0.0.1/test" - - export S3_CONNECTION="s3://aaa:12345678@us-east-1/mybucket?create=true&endpoint=http://127.0.0.1:9000" - - export DYNAMODB_CONNECTION="dynamodb://access_key:secret_key@us-east-1/tablename?endpoint=http://127.0.0.1:8000" - -install: - - php -i - - composer install - -script: - - vendor/bin/phpunit - -jobs: - include: - - stage: documentation - if: branch = master - before_install: skip - install: skip - script: "curl https://opensource.byjg.com/add-doc.sh | bash /dev/stdin php anydataset-nosql docs" diff --git a/README.md b/README.md index dca8b35..30e0af3 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,40 @@ # AnyDataset-NoSql +[![Build Status](https://github.com/byjg/php-anydataset-nosql/actions/workflows/phpunit.yml/badge.svg?branch=master)](https://github.com/byjg/php-anydataset-nosql/actions/workflows/phpunit.yml) [![Opensource ByJG](https://img.shields.io/badge/opensource-byjg-success.svg)](http://opensource.byjg.com) -[![GitHub source](https://img.shields.io/badge/Github-source-informational?logo=github)](https://github.com/byjg/anydataset-nosql/) -[![GitHub license](https://img.shields.io/github/license/byjg/anydataset-nosql.svg)](https://opensource.byjg.com/opensource/licensing.html) -[![GitHub release](https://img.shields.io/github/release/byjg/anydataset-nosql.svg)](https://github.com/byjg/anydataset-nosql/releases/) -[![Build Status](https://travis-ci.com/byjg/anydataset-nosql.svg?branch=master)](https://travis-ci.com/byjg/anydataset-nosql) +[![GitHub source](https://img.shields.io/badge/Github-source-informational?logo=github)](https://github.com/byjg/php-anydataset-nosql/) +[![GitHub license](https://img.shields.io/github/license/byjg/php-anydataset-nosql.svg)](https://opensource.byjg.com/opensource/licensing.html) +[![GitHub release](https://img.shields.io/github/release/byjg/php-anydataset-nosql.svg)](https://github.com/byjg/php-anydataset-nosql/releases/) +Anydataset NoSQL standardize the access to non-relational databases/repositories and treat them as Key/Value. +The implementation can work with: -NoSql abstraction dataset. Anydataset is an agnostic data source abstraction layer in PHP. +- MongoDB +- Cloudflare KV +- S3 +- DynamoDB + +Anydataset is an agnostic data source abstraction layer in PHP. See more about Anydataset [here](https://opensource.byjg.com/php/anydataset). + +## Features + +- Access as Key/Value repositories different datasource +- Allow put and get data +- Simplified way to connect to the datasources + +## Connection Based on URI + +The connection string for databases is based on URL. + +See below the current implemented drivers: + +| Datasource | Connection String | +|---------------------------------------------|----------------------------------------------------------| +| [MongoDB](docs/MongoDB.md) | mongodb://username:password@hostname:port/database | +| [Cloudflare KV](docs/CloudFlareKV.md) | kv://username:password@accountid/namespaceid | +| [S3](docs/AwsS3KeyValue.md) | s3://accesskey:secretkey@region/bucket?params | +| [AWS DynamoDB](docs/AwsDynamoDbKeyValue.md) | dynamodb://accesskey:secretkey@hostname/tablename?params | -See more about Anydataset [here](https://opensource.byjg.com/php/anydataset). ## Examples @@ -20,12 +45,16 @@ Check implementation examples on [https://opensource.byjg.com/php/anydataset-nos Just type: ```bash -composer require "byjg/anydataset-nosql=4.1.*" +composer require "byjg/anydataset-nosql" ``` ## Running Unit tests ```bash +docker-compose up -d +export MONGODB_CONNECTION="mongodb://127.0.0.1/test" +export S3_CONNECTION="s3://aaa:12345678@us-east-1/mybucket?create=true&endpoint=http://127.0.0.1:4566" +export DYNAMODB_CONNECTION="dynamodb://accesskey:secretkey@us-east-1/tablename?endpoint=http://127.0.0.1:8000" vendor/bin/phpunit ``` @@ -40,13 +69,13 @@ Set the environment variable: Set the environment variable: -- DYNAMODB_CONNECTION = "dynamodb://access_key:secret_key@region/tablename" +- DYNAMODB_CONNECTION = "dynamodb://accesskey:secretkey@region/tablename" ### Setup AWS S3 for the unit test Set the environment variable: -- S3_CONNECTION = "s3://access_key:secret_key@region/bucketname" +- S3_CONNECTION = "s3://accesskey:secretkey@region/bucketname" ### Cloudflare KV @@ -55,7 +84,18 @@ Set the environment variable: - CLOUDFLAREKV_CONNECTION = "kv://email:authkey@accountid/namespaceid" - +## Dependencies + +```mermaid +flowchart TD + byjg/anydataset-nosql --> ext-curl + byjg/anydataset-nosql --> aws/aws-sdk-php + byjg/anydataset-nosql --> byjg/anydataset + byjg/anydataset-nosql --> byjg/anydataset-array + byjg/anydataset-nosql --> byjg/serializer + byjg/anydataset-nosql --> byjg/webrequest + byjg/anydataset-nosql --> ext-json +``` ---- [Open source ByJG](http://opensource.byjg.com) diff --git a/composer.json b/composer.json index d18be2a..4392993 100644 --- a/composer.json +++ b/composer.json @@ -9,21 +9,21 @@ "prefer-stable": true, "minimum-stability": "dev", "require": { - "php": ">=5.6.0", + "php": ">=7.4", "ext-curl": "*", "aws/aws-sdk-php": "3.*", - "byjg/anydataset": "4.1.*", - "byjg/anydataset-array": "4.1.*", - "byjg/serializer": "1.0.*", - "byjg/webrequest": "2.0.*", + "byjg/anydataset": "4.9.*", + "byjg/anydataset-array": "4.9.*", + "byjg/serializer": "4.9.*", + "byjg/webrequest": "4.9.*", "ext-json": "*" }, "require-dev": { - "phpunit/phpunit": "5.7.*|7.4.*" + "phpunit/phpunit": "5.7.*|7.4.*|^9.6" }, "suggest": { "ext-mongodb": "*", - "byjg/cache-engine": "4.0.*" + "byjg/cache-engine": "4.9.*" }, "license": "MIT" } diff --git a/docker-compose.yml b/docker-compose.yml index 2f3166d..ed008e5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: '2.0' +version: '3.0' services: mongodb: @@ -7,20 +7,33 @@ services: environment: TZ: America/Winnipeg ports: - - 27017:27017 + - "27017:27017" dynanodb: container_name: anydataset_nosql_dynamodb image: amazon/dynamodb-local ports: - - 8000:8000 + - "8000:8000" + +# s3: +# container_name: anydataset_nosql_s3 +# image: minio/minio +# environment: +# MINIO_ACCESS_KEY: aaa +# MINIO_SECRET_KEY: 12345678 +## command: ["server", "/data"] +# ports: +# - 9000:9000 s3: container_name: anydataset_nosql_s3 - image: minio/minio - environment: - MINIO_ACCESS_KEY: aaa - MINIO_SECRET_KEY: 12345678 - command: ["server", "/data"] + image: localstack/localstack ports: - - 9000:9000 + - "4566:4566" + environment: + - SERVICES=s3 + - DEFAULT_REGION=us-west-1 + - AWS_DEFAULT_REGION=us-west-1 + - HOSTNAME_EXTERNAL=localhost + - USE_SSL=false + - DEBUG=1 \ No newline at end of file diff --git a/docs/AwsDynamoDbKeyValue.md b/docs/AwsDynamoDbKeyValue.md index dbf807c..5fa0534 100644 --- a/docs/AwsDynamoDbKeyValue.md +++ b/docs/AwsDynamoDbKeyValue.md @@ -2,7 +2,7 @@ ```php put( 1201, [ @@ -93,7 +93,7 @@ $dynamodb->put( ```php get(1201, $options); /* Should Return: @@ -110,7 +110,7 @@ $value = $dynamodb->get(1201, $options); ```php remove(1201); ``` @@ -123,7 +123,7 @@ Example: ```php [ diff --git a/docs/AwsS3KeyValue.md b/docs/AwsS3KeyValue.md index 5677777..639749b 100644 --- a/docs/AwsS3KeyValue.md +++ b/docs/AwsS3KeyValue.md @@ -2,7 +2,7 @@ ```php getIterator(); print_r($iterator->toArray()); ``` @@ -47,7 +47,7 @@ print_r($iterator->toArray()); ```php put("object_name", "value"); ``` @@ -55,7 +55,7 @@ $s3->put("object_name", "value"); ```php get("object_name"); ``` @@ -63,7 +63,7 @@ $value = $s3->get("object_name"); ```php remove("object_name"); ``` @@ -71,7 +71,7 @@ $s3->remove("object_name"); ```php getIterator(); print_r($iterator->toArray()); ``` @@ -18,7 +18,7 @@ You can add some a prefix to search and a limit to search: ```php getIterator([ "prefix" => "prefix_to_match", "limit" => 30 @@ -36,7 +36,7 @@ print_r($iterator->toArray()); ```php put("object_name", "value"); ``` @@ -44,7 +44,7 @@ Put Bulk: ```php putBatch($bulk); ```php get("object_name"); ``` @@ -65,7 +65,7 @@ $value = $kv->get("object_name"); ```php remove("object_name"); // or diff --git a/docs/MongoDB.md b/docs/MongoDB.md index fa574c0..a615fb8 100644 --- a/docs/MongoDB.md +++ b/docs/MongoDB.md @@ -2,7 +2,7 @@ ```php getDocumentById($id); if (!empty($document)) { print_r($document->getIdDocument()); @@ -75,7 +75,7 @@ if (!empty($document)) { ```php getDocuments(null, 'mycollection'); foreach ($result as $document) { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index f692b8d..e44d77d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -7,22 +7,29 @@ and open the template in the editor. + + + + + + ./src - + - ./tests + ./tests/ - - + \ No newline at end of file diff --git a/src/AwsDynamoDbDriver.php b/src/AwsDynamoDbDriver.php index d4f0e8b..d791fa0 100644 --- a/src/AwsDynamoDbDriver.php +++ b/src/AwsDynamoDbDriver.php @@ -6,11 +6,11 @@ use Aws\Result; use ByJG\AnyDataset\Core\GenericIterator; use ByJG\AnyDataset\Lists\ArrayDataset; -use ByJG\Serializer\BinderObject; +use ByJG\Serializer\SerializerObject; use ByJG\Util\Uri; use InvalidArgumentException; -class AwsDynamoDbDriver implements KeyValueInterface +class AwsDynamoDbDriver implements KeyValueInterface, RegistrableInterface { /** @@ -100,7 +100,7 @@ protected function prepareToSend($array, $options) { } $val = [ - isset($options['Types']) && isset($options['Types'][$key]) ? $options['Types'][$key] : "S" => $val + $options['Types'][$key] ?? "S" => $val ]; }); @@ -156,12 +156,11 @@ public function get($key, $options = []) * @param $value * @param array $options * @return Result - * @throws \ByJG\Serializer\Exception\InvalidArgumentException */ public function put($key, $value, $options = []) { if (is_object($value)) { - $value = BinderObject::toArrayFrom($value); + $value = SerializerObject::instance($value)->serialize(); } $this->validateOptions($options); @@ -213,11 +212,11 @@ public function getDbConnection() } /** - * @param object[] $key + * @param object[] $keys * @param array $options - * @return mixed + * @return void */ - public function removeBatch($key, $options = []) + public function removeBatch($keys, $options = []) { // TODO: Implement removeBatch() method. } @@ -229,4 +228,9 @@ public function getTablename() { public function client() { return $this->dynamoDbClient; } + + public static function schema() + { + return ["dynamo", "dynamodb"]; + } } diff --git a/src/AwsS3Driver.php b/src/AwsS3Driver.php index 9148794..1b4b59f 100644 --- a/src/AwsS3Driver.php +++ b/src/AwsS3Driver.php @@ -2,14 +2,19 @@ namespace ByJG\AnyDataset\NoSql; -use Aws\Result; +use Aws\S3\Exception\S3Exception; use Aws\S3\S3Client; use ByJG\AnyDataset\Core\GenericIterator; use ByJG\AnyDataset\Lists\ArrayDataset; use ByJG\Util\Uri; -class AwsS3Driver implements KeyValueInterface +class AwsS3Driver implements KeyValueInterface, RegistrableInterface { + const PARAM_BUCKET_ENDPOINT = 'bucket_endpoint'; + const PARAM_USE_ARN_REGION = 'use_arn_region'; + const PARAM_USE_ACCELERATE_ENDPOINT = 'use_accelerate_endpoint'; + const PARAM_USE_PATH_STYLE_ENDPOINT = 'use_path_style_endpoint'; + const PARAM_DISABLE_MULTIREGION_ACCESS_POINTS = 'disable_multiregion_access_points'; /** * @var S3Client @@ -51,17 +56,29 @@ public function __construct($connectionString) unset($extraParameters["create"]); } - $s3Parameters = array_merge($defaultParameters, $extraParameters); + $s3Parameters = []; + foreach (array_merge($defaultParameters, $extraParameters) as $key => $value) { + if (is_string($value)) { + if (strtolower($value) === "true") { + $value = true; + } elseif (strtolower($value) === "false") { + $value = false; + } elseif (is_numeric($value)) { + $value = 0 + $value; + } + } + $s3Parameters[$key] = $value; + } $this->s3Client = new S3Client($s3Parameters); $this->bucket = preg_replace('~^/~', '', $uri->getPath()); try { - $result = $this->s3Client->headBucket([ + $this->s3Client->headBucket([ 'Bucket' => $this->bucket, ]); - } catch (\Aws\S3\Exception\S3Exception $ex) { + } catch (S3Exception $ex) { if (strpos($ex->getMessage(), "404") !== false && $createBucket) { $this->s3Client->createBucket([ 'ACL' => 'private', @@ -89,9 +106,6 @@ public function getIterator($options = []) $options ); - /** - * @var Result - */ $result = $this->s3Client->listObjects($data); $contents = []; @@ -165,7 +179,7 @@ public function getChunk($key, $options = [], $size = 1024, $offset = 0) $options = array_merge( $options, [ - 'Range' => "bytes=${part}-${untilByte}" + 'Range' => "bytes=$part-$untilByte" ] ); @@ -183,11 +197,11 @@ public function putBatch($keyValueArray, $options = []) } /** - * @param object[] $key + * @param object[] $keys * @param array $options - * @return mixed + * @return void */ - public function removeBatch($key, $options = []) + public function removeBatch($keys, $options = []) { // TODO: Implement removeBatch() method. } @@ -195,4 +209,9 @@ public function removeBatch($key, $options = []) public function client() { return $this->s3Client; } + + public static function schema() + { + return "s3"; + } } diff --git a/src/CloudflareKV.php b/src/CloudflareKV.php index 402fa54..d97e89d 100644 --- a/src/CloudflareKV.php +++ b/src/CloudflareKV.php @@ -4,19 +4,18 @@ use ByJG\AnyDataset\Core\IteratorInterface; use ByJG\AnyDataset\Lists\ArrayDataset; -use ByJG\Serializer\BinderObject; -use ByJG\Serializer\Exception\InvalidArgumentException; +use ByJG\Serializer\SerializerObject; use ByJG\Util\Exception\CurlException; +use ByJG\Util\Exception\MessageException; use ByJG\Util\HttpClient; +use ByJG\Util\Psr7\MemoryStream; use ByJG\Util\Psr7\Message; -use ByJG\Util\Psr7\MessageException; use ByJG\Util\Psr7\Request; use ByJG\Util\Uri; -use MintWare\Streams\MemoryStream; use Psr\Http\Message\MessageInterface; use Psr\Http\Message\RequestInterface; -class CloudflareKV implements KeyValueInterface +class CloudflareKV implements KeyValueInterface, RegistrableInterface { protected $username; protected $password; @@ -79,7 +78,6 @@ public function put($key, $value, $options = []) * @param KeyValueDocument[] $keyValueArray * @param array $options * @return mixed|void - * @throws InvalidArgumentException * @throws CurlException * @throws MessageException */ @@ -88,7 +86,7 @@ public function putBatch($keyValueArray, $options = []) $request = $this->request("/bulk", $options) ->withMethod("put") ->withHeader("Content-Type", "application/json") - ->withBody(new MemoryStream(json_encode(BinderObject::toArrayFrom($keyValueArray)))); + ->withBody(new MemoryStream(json_encode(SerializerObject::instance($keyValueArray)->serialize()))); return $this->checkResult( $this->send($request) @@ -100,6 +98,7 @@ public function putBatch($keyValueArray, $options = []) * @param array $options * @return string * @throws CurlException + * @throws MessageException */ public function remove($key, $options = []) { @@ -136,7 +135,7 @@ public function removeBatch($keys, $options = []) */ protected function send(RequestInterface $request) { - return $client = HttpClient::getInstance() + return HttpClient::getInstance() ->sendRequest($request)->getBody()->getContents(); } @@ -202,10 +201,15 @@ protected function checkResult($str) if (isset($array["success"]) && !$array["success"]) { $errorMsg = ""; foreach ($array["errors"] as $error) { - $errorMsg .= "[${error["code"]}] ${error["message"]}\n"; + $errorMsg .= "[{$error["code"]}] {$error["message"]}\n"; } throw new CurlException($errorMsg); } return $array; } + + public static function schema() + { + return "kv"; + } } diff --git a/src/Factory.php b/src/Factory.php index b4f9c4d..d001895 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -2,84 +2,62 @@ namespace ByJG\AnyDataset\NoSql; -use ByJG\AnyDataset\Core\Exception\NotAvailableException; use ByJG\Util\Uri; +use InvalidArgumentException; class Factory { - /** - * @param $connectionString - * @param $schemesAlternative - * @return NoSqlInterface - * @throws NotAvailableException - */ - public static function getNoSqlInstance($connectionString, $schemesAlternative = null) - { - $prefix = '\\ByJG\\AnyDataset\\NoSql\\'; - - return self::getInstance( - $connectionString, - array_merge( - [ - "mongodb" => $prefix . "MongoDbDriver", - ], - (array)$schemesAlternative - ), - NoSqlInterface::class - ); - } + private static $config = []; /** - * @param string $connectionString - * @param array $schemesAlternative - * @return KeyValueInterface - * @throws NotAvailableException + * @param string $class + * @return void */ - public static function getKeyValueInstance($connectionString, $schemesAlternative = null) + public static function registerDriver($class) { - $prefix = '\\ByJG\\AnyDataset\\NoSql\\'; + if (!in_array(RegistrableInterface::class, class_implements($class))) { + throw new InvalidArgumentException( + "The class '$class' is not a valid instance" + ); + } + + if (empty($class::schema())) { + throw new InvalidArgumentException( + "The class '$class' must implement the static method schema()" + ); + } - return self::getInstance( - $connectionString, - array_merge( - [ - "s3" => $prefix . "AwsS3Driver", - "dynamodb" => $prefix . "AwsDynamoDbDriver", - "kv" => $prefix . "CloudflareKV", - ], - (array)$schemesAlternative - ), - KeyValueInterface::class - ); + $protocolList = $class::schema(); + foreach ((array)$protocolList as $item) { + self::$config[$item] = $class; + } } /** - * @param $connectionString - * @param $validSchemes - * @param $typeOf - * @return mixed - * @throws NotAvailableException + * @param $connectionUri Uri|string + * @return NoSqlInterface|KeyValueInterface */ - protected static function getInstance($connectionString, $validSchemes, $typeOf) + public static function getInstance($connectionUri) { - $connectionUri = new Uri($connectionString); - - $scheme = $connectionUri->getScheme(); - - if (!isset($validSchemes[$scheme])) { - throw new NotAvailableException("Not available: " . $scheme); + if (empty(self::$config)) { + self::registerDriver(AwsDynamoDbDriver::class); + self::registerDriver(AwsS3Driver::class); + self::registerDriver(CloudflareKV::class); + self::registerDriver(MongoDbDriver::class); } - $class = $validSchemes[$scheme]; + if (is_string($connectionUri)) { + $connectionUri = new Uri($connectionUri); + } - $instance = new $class($connectionUri); + $scheme = $connectionUri->getScheme(); - if (!is_a($instance, $typeOf)) { - throw new \InvalidArgumentException( - "The class '$typeOf' is not a instance of DbDriverInterface" - ); + if (!isset(self::$config[$scheme])) { + throw new InvalidArgumentException("The '$scheme' scheme does not exist."); } - return $instance; + $class = self::$config[$scheme]; + + return new $class($connectionUri); } } diff --git a/src/MongoDbDriver.php b/src/MongoDbDriver.php index 8a2afaf..67ba103 100644 --- a/src/MongoDbDriver.php +++ b/src/MongoDbDriver.php @@ -2,10 +2,12 @@ namespace ByJG\AnyDataset\NoSql; -use ByJG\AnyDataset\Core\IteratorFilter; use ByJG\AnyDataset\Core\Enum\Relation; -use ByJG\Serializer\BinderObject; +use ByJG\AnyDataset\Core\IteratorFilter; +use ByJG\Serializer\SerializerObject; use ByJG\Util\Uri; +use DateTime; +use InvalidArgumentException; use MongoDB\BSON\Binary; use MongoDB\BSON\Decimal128; use MongoDB\BSON\Javascript; @@ -13,11 +15,12 @@ use MongoDB\BSON\Timestamp; use MongoDB\BSON\UTCDateTime; use MongoDB\Driver\BulkWrite; +use MongoDB\Driver\Exception\Exception; use MongoDB\Driver\Manager; use MongoDB\Driver\Query; use MongoDB\Driver\WriteConcern; -class MongoDbDriver implements NoSqlInterface +class MongoDbDriver implements NoSqlInterface, RegistrableInterface { /** * @var array @@ -98,9 +101,8 @@ public function getDbConnection() /** * @param $idDocument * @param null $collection - * @return \ByJG\AnyDataset\NoSql\NoSqlDocument|null - * @throws \MongoDB\Driver\Exception\Exception - * @throws \ByJG\Serializer\Exception\InvalidArgumentException + * @return NoSqlDocument|null + * @throws Exception */ public function getDocumentById($idDocument, $collection = null) { @@ -116,16 +118,15 @@ public function getDocumentById($idDocument, $collection = null) } /** - * @param \ByJG\AnyDataset\Core\IteratorFilter $filter + * @param IteratorFilter $filter * @param null $collection - * @return \ByJG\AnyDataset\NoSql\NoSqlDocument[]|null - * @throws \MongoDB\Driver\Exception\Exception - * @throws \ByJG\Serializer\Exception\InvalidArgumentException + * @return NoSqlDocument[]|null + * @throws Exception */ public function getDocuments(IteratorFilter $filter, $collection = null) { if (empty($collection)) { - throw new \InvalidArgumentException('Collection is mandatory for MongoDB'); + throw new InvalidArgumentException('Collection is mandatory for MongoDB'); } $dataCursor = $this->mongoManager->executeQuery( @@ -144,7 +145,9 @@ public function getDocuments(IteratorFilter $filter, $collection = null) $result[] = new NoSqlDocument( $item->_id, $collection, - BinderObject::toArrayFrom($item, false, $this->excludeMongoClass) + SerializerObject::instance($item) + ->withDoNotParse($this->excludeMongoClass) + ->serialize() ); } @@ -161,11 +164,11 @@ protected function getMongoFilterArray(IteratorFilter $filter) $value = $itemFilter[3]; if ($itemFilter[0] == ' or ') { - throw new \InvalidArgumentException('MongoDBDriver does not support the addRelationOr'); + throw new InvalidArgumentException('MongoDBDriver does not support the addRelationOr'); } if (isset($result[$name])) { - throw new \InvalidArgumentException('MongoDBDriver does not support filtering the same field twice'); + throw new InvalidArgumentException('MongoDBDriver does not support filtering the same field twice'); } $data = [ @@ -212,7 +215,7 @@ public function deleteDocumentById($idDocument, $collection = null) public function deleteDocuments(IteratorFilter $filter, $collection = null) { if (empty($collection)) { - throw new \InvalidArgumentException('Collection is mandatory for MongoDB'); + throw new InvalidArgumentException('Collection is mandatory for MongoDB'); } $writeConcern = new WriteConcern(WriteConcern::MAJORITY, 100); @@ -227,30 +230,31 @@ public function deleteDocuments(IteratorFilter $filter, $collection = null) } /** - * @param \ByJG\AnyDataset\NoSql\NoSqlDocument $document - * @return \ByJG\AnyDataset\NoSql\NoSqlDocument - * @throws \ByJG\Serializer\Exception\InvalidArgumentException + * @param NoSqlDocument $document + * @return NoSqlDocument */ public function save(NoSqlDocument $document) { if (empty($document->getCollection())) { - throw new \InvalidArgumentException('Collection is mandatory for MongoDB'); + throw new InvalidArgumentException('Collection is mandatory for MongoDB'); } $writeConcern = new WriteConcern(WriteConcern::MAJORITY, 100); $bulkWrite = new BulkWrite(); - $data = BinderObject::toArrayFrom($document->getDocument(), false, $this->excludeMongoClass); + $data = SerializerObject::instance($document->getDocument()) + ->withDoNotParse($this->excludeMongoClass) + ->serialize(); $idDocument = $document->getIdDocument(); if (empty($idDocument)) { - $idDocument = isset($data['_id']) ? $data['_id'] : null; + $idDocument = $data['_id'] ?? null; } - $data['updated'] = new UTCDateTime((new \DateTime())->getTimestamp()*1000); + $data['updated'] = new UTCDateTime((new DateTime())->getTimestamp()*1000); if (empty($idDocument)) { $data['_id'] = $idDocument = new ObjectID(); - $data['created'] = new UTCDateTime((new \DateTime())->getTimestamp()*1000); + $data['created'] = new UTCDateTime((new DateTime())->getTimestamp()*1000); $bulkWrite->insert($data); } else { $data['_id'] = $idDocument; @@ -268,4 +272,9 @@ public function save(NoSqlDocument $document) return $document; } + + public static function schema() + { + return "mongodb"; + } } diff --git a/src/NoSqlInterface.php b/src/NoSqlInterface.php index 19e9bc9..f00ef85 100644 --- a/src/NoSqlInterface.php +++ b/src/NoSqlInterface.php @@ -17,14 +17,14 @@ interface NoSqlInterface public function getDocumentById($idDocument, $collection = null); /** - * @param \ByJG\AnyDataset\Core\IteratorFilter $filter + * @param IteratorFilter $filter * @param null $collection * @return NoSqlDocument[]|null */ public function getDocuments(IteratorFilter $filter, $collection = null); /** - * @param \ByJG\AnyDataset\NoSql\NoSqlDocument $document + * @param NoSqlDocument $document * @return NoSqlDocument */ public function save(NoSqlDocument $document); @@ -37,7 +37,7 @@ public function save(NoSqlDocument $document); public function deleteDocumentById($idDocument, $collection = null); /** - * @param \ByJG\AnyDataset\Core\IteratorFilter $filter + * @param IteratorFilter $filter * @param null $collection * @return mixed */ diff --git a/src/RegistrableInterface.php b/src/RegistrableInterface.php new file mode 100644 index 0000000..a740f94 --- /dev/null +++ b/src/RegistrableInterface.php @@ -0,0 +1,8 @@ +object = Factory::getKeyValueInstance($awsConnection); + $this->object = Factory::getInstance($awsConnection); $this->createTable(); @@ -81,7 +79,7 @@ protected function createTable() } } - protected function tearDown() + protected function tearDown(): void { if (!empty($this->object)) { $this->object->remove(1, $this->options); @@ -90,6 +88,9 @@ protected function tearDown() } } + /** + * @throws \ByJG\Serializer\Exception\InvalidArgumentException + */ public function testDynamoDbOperations() { if (empty($this->object)) { diff --git a/tests/AwsS3DriverTest.php b/tests/AwsS3DriverTest.php index 0e6ed68..54c38f9 100644 --- a/tests/AwsS3DriverTest.php +++ b/tests/AwsS3DriverTest.php @@ -1,9 +1,8 @@ object = Factory::getKeyValueInstance($awsConnection); + $uri = new Uri($awsConnection); + $uri = $uri->withQueryKeyValue("use_path_style_endpoint", "true"); + $this->object = Factory::getInstance($uri); $this->object->remove("KEY"); $this->object->remove("ANOTHER"); } } - protected function tearDown() + protected function tearDown(): void { if (!empty($this->object)) { $this->object->remove("KEY"); @@ -76,7 +77,7 @@ public function testGetChunk() str_repeat("0", 256) . str_repeat("1", 256) . str_repeat("2", 250) ); - $part1 = $this->object->getChunk("KEY", [], 256, 0); + $part1 = $this->object->getChunk("KEY", [], 256); $part2 = $this->object->getChunk("KEY", [], 256, 1); $part3 = $this->object->getChunk("KEY", [], 256, 2); diff --git a/tests/MongoDbDriverTest.php b/tests/MongoDbDriverTest.php index 4211c96..4ed1ac3 100644 --- a/tests/MongoDbDriverTest.php +++ b/tests/MongoDbDriverTest.php @@ -1,12 +1,10 @@ dbDriver = Factory::getNoSqlInstance($mongodbConnection); + $this->dbDriver = Factory::getInstance($mongodbConnection); $this->dbDriver->save( new NoSqlDocument( @@ -72,13 +70,16 @@ public function setUp() ); } - public function tearDown() + public function tearDown(): void { if (!empty($this->dbDriver)) { $this->dbDriver->deleteDocuments(new IteratorFilter(), self::TEST_COLLECTION); } } + /** + * @throws \MongoDB\Driver\Exception\Exception + */ public function testSaveDocument() { if (empty($this->dbDriver)) { @@ -90,8 +91,8 @@ public function testSaveDocument() $filter->addRelation('name', Relation::EQUAL, 'Hilux'); $document = $this->dbDriver->getDocuments($filter, self::TEST_COLLECTION); - // Check if get ONe - $this->assertEquals(1, count($document)); + // Check if returns one document + $this->assertCount(1, $document); // Check if the default fields are here $data = $document[0]->getDocument(); @@ -137,6 +138,9 @@ public function testSaveDocument() ); } + /** + * @throws \MongoDB\Driver\Exception\Exception + */ public function testDelete() { if (empty($this->dbDriver)) { @@ -147,16 +151,19 @@ public function testDelete() $filter = new IteratorFilter(); $filter->addRelation('name', Relation::EQUAL, 'Uno'); $document = $this->dbDriver->getDocuments($filter, self::TEST_COLLECTION); - $this->assertEquals(1, count($document)); + $this->assertCount(1, $document); // Delete $this->dbDriver->deleteDocuments($filter, self::TEST_COLLECTION); - // Check if object does not exists + // Check if object do not exist $document = $this->dbDriver->getDocuments($filter, self::TEST_COLLECTION); $this->assertEmpty($document); } + /** + * @throws \MongoDB\Driver\Exception\Exception + */ public function testGetDocuments() { if (empty($this->dbDriver)) { @@ -166,7 +173,7 @@ public function testGetDocuments() $filter = new IteratorFilter(); $filter->addRelation('price', Relation::LESS_OR_EQUAL_THAN, 40000); $documents = $this->dbDriver->getDocuments($filter, self::TEST_COLLECTION); - $this->assertEquals(2, count($documents)); + $this->assertCount(2, $documents); $this->assertEquals('Fox', $documents[0]->getDocument()['name']); $this->assertEquals('Volkswagen', $documents[0]->getDocument()['brand']); $this->assertEquals('40000', $documents[0]->getDocument()['price']); @@ -177,7 +184,7 @@ public function testGetDocuments() $filter = new IteratorFilter(); $filter->addRelation('price', Relation::LESS_THAN, 40000); $documents = $this->dbDriver->getDocuments($filter, self::TEST_COLLECTION); - $this->assertEquals(1, count($documents)); + $this->assertCount(1, $documents); $this->assertEquals('Uno', $documents[0]->getDocument()['name']); $this->assertEquals('Fiat', $documents[0]->getDocument()['brand']); $this->assertEquals('35000', $documents[0]->getDocument()['price']); @@ -185,7 +192,7 @@ public function testGetDocuments() $filter = new IteratorFilter(); $filter->addRelation('price', Relation::GREATER_OR_EQUAL_THAN, 90000); $documents = $this->dbDriver->getDocuments($filter, self::TEST_COLLECTION); - $this->assertEquals(2, count($documents)); + $this->assertCount(2, $documents); $this->assertEquals('Hilux', $documents[0]->getDocument()['name']); $this->assertEquals('Toyota', $documents[0]->getDocument()['brand']); $this->assertEquals('120000', $documents[0]->getDocument()['price']); @@ -196,7 +203,7 @@ public function testGetDocuments() $filter = new IteratorFilter(); $filter->addRelation('price', Relation::GREATER_THAN, 90000); $documents = $this->dbDriver->getDocuments($filter, self::TEST_COLLECTION); - $this->assertEquals(1, count($documents)); + $this->assertCount(1, $documents); $this->assertEquals('Hilux', $documents[0]->getDocument()['name']); $this->assertEquals('Toyota', $documents[0]->getDocument()['brand']); $this->assertEquals('120000', $documents[0]->getDocument()['price']); @@ -204,7 +211,7 @@ public function testGetDocuments() $filter = new IteratorFilter(); $filter->addRelation('name', Relation::STARTS_WITH, 'Co'); $documents = $this->dbDriver->getDocuments($filter, self::TEST_COLLECTION); - $this->assertEquals(2, count($documents)); + $this->assertCount(2, $documents); $this->assertEquals('Corolla', $documents[0]->getDocument()['name']); $this->assertEquals('Toyota', $documents[0]->getDocument()['brand']); $this->assertEquals('80000', $documents[0]->getDocument()['price']); @@ -215,7 +222,7 @@ public function testGetDocuments() $filter = new IteratorFilter(); $filter->addRelation('name', Relation::CONTAINS, 'oba'); $documents = $this->dbDriver->getDocuments($filter, self::TEST_COLLECTION); - $this->assertEquals(1, count($documents)); + $this->assertCount(1, $documents); $this->assertEquals('Cobalt', $documents[0]->getDocument()['name']); $this->assertEquals('Chevrolet', $documents[0]->getDocument()['brand']); $this->assertEquals('60000', $documents[0]->getDocument()['price']);