You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by is...@apache.org on 2018/10/09 14:42:50 UTC
[1/9] ignite git commit: IGNITE-7783: PHP thin client
Repository: ignite
Updated Branches:
refs/heads/master 1415c6100 -> 7d3ea1155
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/tests/TestingHelper.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/TestingHelper.php b/modules/platforms/php/tests/TestingHelper.php
new file mode 100644
index 0000000..2ff3537
--- /dev/null
+++ b/modules/platforms/php/tests/TestingHelper.php
@@ -0,0 +1,363 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+use \DateTime;
+use Ds\Map;
+use Ds\Set;
+use Brick\Math\BigDecimal;
+use PHPUnit\Framework\TestCase;
+use Apache\Ignite\Client;
+use Apache\Ignite\ClientConfiguration;
+use Apache\Ignite\Exception\OperationException;
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Data\Date;
+use Apache\Ignite\Data\Time;
+use Apache\Ignite\Data\Timestamp;
+use Apache\Ignite\Data\BinaryObject;
+
+/**
+ * Helper class for testing apache-ignite-client library.
+ * Contains common methods for testing environment initialization and cleanup.
+ */
+class TestingHelper
+{
+ public static $client;
+ public static $primitiveValues;
+ public static $arrayValues;
+
+ /**
+ * Initializes testing environment: creates and starts the library client, sets default jasmine test timeout.
+ * Should be called from any test case setUpBeforeClass method.
+ */
+ public static function init(): void
+ {
+ TestingHelper::$client = new Client();
+ TestingHelper::$client->setDebug(TestConfig::$debug);
+ TestingHelper::$client->connect(new ClientConfiguration(...TestConfig::$endpoints));
+ TestingHelper::initValues();
+ }
+
+ /**
+ * Cleans up testing environment.
+ * Should be called from any test case tearDownAfterClass method.
+ */
+ public static function cleanUp(): void
+ {
+ TestingHelper::$client->disconnect();
+ }
+
+ public static function destroyCache(string $cacheName): void
+ {
+ try {
+ TestingHelper::$client->destroyCache($cacheName);
+ } catch (OperationException $e) {
+ //expected exception
+ }
+ }
+
+ public static function executeExample(string $name, TestCase $testCase, array $outputChecker): void
+ {
+ $output = null;
+ $return_var = 0;
+ exec('php ' . __DIR__ . '/../examples/' . $name, $output, $return_var);
+ TestingHelper::logDebug(print_r($output, true));
+ $testCase->assertEquals($return_var, 0);
+ foreach ($output as $out) {
+ call_user_func($outputChecker, $output);
+ }
+ }
+
+ public static function compare($value1, $value2): bool
+ {
+ TestingHelper::logDebug(sprintf('compare: %s and %s', TestingHelper::printValue($value1), TestingHelper::printValue($value2)));
+ if ($value1 === null && $value2 === null) {
+ return true;
+ } elseif ($value1 === null && $value2 !== null || $value1 !== null && $value2 === null) {
+ return false;
+ } elseif (gettype($value1) === 'double' || gettype($value2) === 'double') {
+ return TestingHelper::floatComparator($value1, $value2);
+ } elseif (gettype($value1) !== gettype($value2)) {
+ TestingHelper::logDebug(sprintf('compare: value types are different: %s and %s',
+ gettype($value1), gettype($value2)));
+ return false;
+ } elseif (is_array($value1) && is_array($value2)) {
+ if (count($value1) !== count($value2)) {
+ TestingHelper::logDebug('compare: array lengths are different');
+ return false;
+ }
+ foreach ($value1 as $key => $val1) {
+ $val2 = $value2[$key];
+ if (!TestingHelper::compare($val1, $val2)) {
+ TestingHelper::logDebug(sprintf('compare: array elements are different: %s, %s',
+ TestingHelper::printValue($val1), TestingHelper::printValue($val2)));
+ return false;
+ }
+ }
+ return true;
+ } elseif (gettype($value1) !== 'object') {
+ return TestingHelper::defaultComparator($value1, $value2);
+ } elseif ($value1 instanceof Time && $value2 instanceof Time) {
+ return TestingHelper::defaultComparator($value1->getMillis(), $value2->getMillis());
+ } elseif ($value1 instanceof Timestamp && $value2 instanceof Timestamp) {
+ return TestingHelper::floatComparator($value1->getMillis(), $value2->getMillis()) &&
+ TestingHelper::defaultComparator($value1->getNanos(), $value2->getNanos());
+ } elseif ($value1 instanceof Date && $value2 instanceof Date) {
+ return TestingHelper::floatComparator($value1->getMillis(), $value2->getMillis());
+ } elseif ($value1 instanceof BigDecimal && $value2 instanceof BigDecimal) {
+ return $value1->isEqualTo($value2);
+ } elseif ($value1 instanceof Map && $value2 instanceof Map) {
+ if ($value1->count() !== $value2->count()) {
+ TestingHelper::logDebug('compare: map sizes are different');
+ return false;
+ }
+ foreach ($value1->pairs() as $pair1) {
+ if (!$value2->hasKey($pair1->key)) {
+ TestingHelper::logDebug(sprintf('compare: maps are different: %s key is absent',
+ TestingHelper::printValue($pair1->key)));
+ return false;
+ }
+ if (!TestingHelper::compare($pair1->value, $value2->get($pair1->key))) {
+ TestingHelper::logDebug(sprintf('compare: map values are different: %s, %s',
+ TestingHelper::printValue($pair1->value), TestingHelper::printValue($value2->get($pair1->key))));
+ return false;
+ }
+ }
+ return true;
+ } elseif ($value1 instanceof Set && $value2 instanceof Set) {
+ if ($value1->count() !== $value2->count()) {
+ TestingHelper::logDebug('compare: set sizes are different');
+ return false;
+ }
+ $value1Arr = $value1->toArray();
+ $value2Arr = $value2->toArray();
+ sort($value1Arr);
+ sort($value2Arr);
+ if (!TestingHelper::compare($value1Arr, $value2Arr)) {
+ TestingHelper::logDebug(sprintf('compare: sets are different: %s and %s',
+ TestingHelper::printValue($value1Arr), TestingHelper::printValue($value2Arr)));
+ return false;
+ }
+ return true;
+ } elseif ($value2 instanceof BinaryObject) {
+ if ($value1 instanceof BinaryObject) {
+ if ($value1->getTypeName() !== $value2->getTypeName()) {
+ TestingHelper::logDebug(sprintf('compare: binary object type names are different'));
+ return false;
+ }
+ if (!TestingHelper::compare($value1->getFieldNames(), $value2->getFieldNames())) {
+ TestingHelper::logDebug(sprintf('compare: binary object field names are different'));
+ return false;
+ }
+ foreach ($value1->getFieldNames() as $fieldName) {
+ if (!$value1->hasField($fieldName) || !$value2->hasField($fieldName) ||
+ !TestingHelper::compare($value1->getField($fieldName), $value2->getField($fieldName))) {
+ TestingHelper::logDebug(sprintf('compare: binary objects field "%s" values are different', $fieldName));
+ return false;
+ }
+ }
+ return true;
+ } else {
+ $reflect1 = new \ReflectionClass($value1);
+ $properties1 = $reflect1->getProperties(\ReflectionProperty::IS_PUBLIC);
+ foreach ($properties1 as $property1) {
+ if ($property1->isStatic()) {
+ continue;
+ }
+ $propName = $property1->getName();
+ $propValue1 = $property1->getValue($value1);
+ $propValue2 = $value2->getField($propName);
+ if (!TestingHelper::compare($propValue1, $propValue2)) {
+ TestingHelper::logDebug(sprintf('compare: binary object values for field %s are different: %s and %s',
+ TestingHelper::printValue($propName), TestingHelper::printValue($propValue1), TestingHelper::printValue($propValue2)));
+ return false;
+ }
+ }
+ return true;
+ }
+ } else {
+ $reflect1 = new \ReflectionClass($value1);
+ $properties1 = $reflect1->getProperties(\ReflectionProperty::IS_PUBLIC);
+ $reflect2 = new \ReflectionClass($value1);
+ foreach ($properties1 as $property1) {
+ if ($property1->isStatic()) {
+ continue;
+ }
+ $propName = $property1->getName();
+ if ($reflect2->hasProperty($propName)) {
+ $property2 = $reflect2->getProperty($propName);
+ if ($property1->getModifiers() !== $property2->getModifiers()) {
+ TestingHelper::logDebug(sprintf(
+ 'compare: objects are different: object property modifiers for property %s are different', $propName));
+ return false;
+ } else {
+ $propValue1 = $property1->getValue($value1);
+ $propValue2 = $property2->getValue($value2);
+ if (!TestingHelper::compare($propValue1, $propValue2)) {
+ TestingHelper::logDebug(sprintf('compare: objects are different, property %s values: %s and %s',
+ $propName, TestingHelper::printValue($propValue1), TestingHelper::printValue($propValue2)));
+ return false;
+ }
+ }
+ } else {
+ TestingHelper::logDebug(sprintf('compare: objects are different: %s property is absent', $propName));
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private static function initValues(): void
+ {
+ TestingHelper::$primitiveValues = [
+ ObjectType::BYTE => [
+ 'values' => [-128, 0, 127],
+ 'isMapKey' => true,
+ 'isArrayKey' => true
+ ],
+ ObjectType::SHORT => [
+ 'values' => [-32768, 0, 32767],
+ 'isMapKey' => true,
+ 'isArrayKey' => true
+ ],
+ ObjectType::INTEGER => [
+ 'values' => [12345, 0, -54321],
+ 'isMapKey' => true,
+ 'isArrayKey' => true,
+ 'typeOptional' => true
+ ],
+ ObjectType::LONG => [
+ 'values' => [12345678912345, 0, -98765432112345],
+ 'isMapKey' => false,
+ 'isArrayKey' => false,
+ ],
+ ObjectType::FLOAT => [
+ 'values' => [-1.155, 0.0, 123e-5],
+ 'isMapKey' => false,
+ 'isArrayKey' => false,
+ ],
+ ObjectType::DOUBLE => [
+ 'values' => [-123e5, 0.0, 0.0001],
+ 'isMapKey' => false,
+ 'isArrayKey' => false,
+ 'typeOptional' => true
+ ],
+ ObjectType::CHAR => [
+ 'values' => ['a', "\xC3\xA1"],
+ 'isMapKey' => true,
+ 'isArrayKey' => true,
+ ],
+ ObjectType::BOOLEAN => [
+ 'values' => [true, false],
+ 'isMapKey' => true,
+ 'isArrayKey' => false,
+ 'typeOptional' => true
+ ],
+ ObjectType::STRING => [
+ 'values' => ['abc', '', '0123'],
+ 'isMapKey' => true,
+ 'isArrayKey' => true,
+ 'typeOptional' => true
+ ],
+ ObjectType::UUID => [
+ 'values' => [
+ [ 18, 70, 2, 119, 154, 254, 198, 254, 195, 146, 33, 60, 116, 230, 0, 146 ],
+ [ 141, 77, 31, 194, 127, 36, 184, 255, 192, 4, 118, 57, 253, 209, 111, 147 ]
+ ],
+ 'isMapKey' => false,
+ 'isArrayKey' => false
+ ],
+ ObjectType::DATE => [
+ 'values' => [
+ Date::fromDateTime(new DateTime('now')),
+ new Date(1234567890),
+ new Date(0)],
+ 'isMapKey' => false,
+ 'isArrayKey' => false,
+ 'typeOptional' => true
+ ],
+ ObjectType::DECIMAL => [
+ 'values' => [
+ BigDecimal::of('123456789.6789345'),
+ BigDecimal::of(0),
+ BigDecimal::of('-98765.4321e15')],
+ 'isMapKey' => false,
+ 'isArrayKey' => false,
+ 'typeOptional' => true
+ ],
+ ObjectType::TIME => [
+ 'values' => [
+ new Time(1234567),
+ new Time(123)],
+ 'isMapKey' => false,
+ 'isArrayKey' => false,
+ 'typeOptional' => true
+ ],
+ ObjectType::TIMESTAMP => [
+ 'values' => [
+ Timestamp::fromDateTime(new DateTime('now')),
+ new Timestamp(12345, 12345),
+ new Timestamp(0, 0)],
+ 'isMapKey' => false,
+ 'isArrayKey' => false,
+ 'typeOptional' => true
+ ],
+ ];
+
+ TestingHelper::$arrayValues = [
+ ObjectType::BYTE_ARRAY => [ 'elemType' => ObjectType::BYTE ],
+ ObjectType::SHORT_ARRAY => [ 'elemType' => ObjectType::SHORT ],
+ ObjectType::INTEGER_ARRAY => [ 'elemType' => ObjectType::INTEGER, 'typeOptional' => true ],
+ ObjectType::LONG_ARRAY => [ 'elemType' => ObjectType::LONG ],
+ ObjectType::FLOAT_ARRAY => [ 'elemType' => ObjectType::FLOAT ],
+ ObjectType::DOUBLE_ARRAY => [ 'elemType' => ObjectType::DOUBLE, 'typeOptional' => true ],
+ ObjectType::CHAR_ARRAY => [ 'elemType' => ObjectType::CHAR ],
+ ObjectType::BOOLEAN_ARRAY => [ 'elemType' => ObjectType::BOOLEAN, 'typeOptional' => true ],
+ ObjectType::STRING_ARRAY => [ 'elemType' => ObjectType::STRING, 'typeOptional' => true ],
+ ObjectType::UUID_ARRAY => [ 'elemType' => ObjectType::UUID ],
+ ObjectType::DATE_ARRAY => [ 'elemType' => ObjectType::DATE, 'typeOptional' => true ],
+ ObjectType::DECIMAL_ARRAY => [ 'elemType' => ObjectType::DECIMAL, 'typeOptional' => true ],
+ ObjectType::TIMESTAMP_ARRAY => [ 'elemType' => ObjectType::TIMESTAMP, 'typeOptional' => true ],
+ ObjectType::TIME_ARRAY => [ 'elemType' => ObjectType::TIME, 'typeOptional' => true ],
+ ];
+ }
+
+ private static function floatComparator(float $value1, float $value2): bool
+ {
+ return abs($value1 - $value2) < 0.0001;
+ }
+
+ private static function defaultComparator($value1, $value2): bool
+ {
+ return $value1 === $value2;
+ }
+
+ public static function printValue($value)
+ {
+ return print_r($value, true);
+ }
+
+ private static function logDebug($message): void
+ {
+ if (TestConfig::$debug) {
+ echo($message . PHP_EOL);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/tests/examples/ExecuteAuthTlsExample.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/examples/ExecuteAuthTlsExample.php b/modules/platforms/php/tests/examples/ExecuteAuthTlsExample.php
new file mode 100644
index 0000000..d947b3c
--- /dev/null
+++ b/modules/platforms/php/tests/examples/ExecuteAuthTlsExample.php
@@ -0,0 +1,36 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+use PHPUnit\Framework\TestCase;
+
+final class ExecuteAuthTlsExampleTestCase extends TestCase
+{
+ public function testAuthTlsExample(): void
+ {
+ TestingHelper::executeExample('AuthTlsExample.php', $this, array($this, 'checkNoErrors'));
+ }
+
+ public function checkNoErrors(array $output): void
+ {
+ foreach ($output as $out) {
+ $this->assertNotContains('ERROR:', $out);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/tests/examples/ExecuteExamples.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/examples/ExecuteExamples.php b/modules/platforms/php/tests/examples/ExecuteExamples.php
new file mode 100644
index 0000000..b347246
--- /dev/null
+++ b/modules/platforms/php/tests/examples/ExecuteExamples.php
@@ -0,0 +1,61 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+use PHPUnit\Framework\TestCase;
+
+final class ExecuteExamplesTestCase extends TestCase
+{
+ public function testCachePutGetExample(): void
+ {
+ TestingHelper::executeExample('CachePutGetExample.php', $this, array($this, 'checkNoErrors'));
+ }
+
+ public function testSqlExample(): void
+ {
+ TestingHelper::executeExample('SqlExample.php', $this, array($this, 'checkNoErrors'));
+ }
+
+ public function testSqlQueryEntriesExample(): void
+ {
+ TestingHelper::executeExample('SqlQueryEntriesExample.php', $this, array($this, 'checkNoErrors'));
+ }
+
+ public function testFailoverExample(): void
+ {
+ TestingHelper::executeExample('FailoverExample.php', $this, array($this, 'checkClientConnected'));
+ }
+
+ public function checkNoErrors(array $output): void
+ {
+ foreach ($output as $out) {
+ $this->assertNotContains('ERROR:', $out);
+ }
+ }
+
+ public function checkClientConnected(array $output): void
+ {
+ foreach ($output as $out) {
+ if (strpos($out, 'Client connected') !== false) {
+ return;
+ }
+ }
+ $this->assertTrue(false);
+ }
+}
[7/9] ignite git commit: IGNITE-7783: PHP thin client
Posted by is...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/composer.json
----------------------------------------------------------------------
diff --git a/modules/platforms/php/composer.json b/modules/platforms/php/composer.json
new file mode 100644
index 0000000..b07c058
--- /dev/null
+++ b/modules/platforms/php/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "apache/apache-ignite-client",
+ "type": "library",
+ "description": "PHP Client for Apache Ignite",
+ "keywords": ["apache", "ignite", "client"],
+ "homepage": "https://github.com/apache/ignite",
+ "license": "Apache-2.0",
+ "authors": [
+ ],
+ "require": {
+ "php": ">=7.2.0",
+ "ext-mbstring": "*",
+ "php-ds/php-ds": "^1.2",
+ "brick/math": "^0.7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.3.1"
+ },
+ "suggest": {
+ },
+ "autoload": {
+ "psr-4": {"Apache\\Ignite\\": "src/Apache/Ignite"}
+ },
+ "autoload-dev": {
+ "psr-4": { "Apache\\Ignite\\Tests\\": "tests/" }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/examples/AuthTlsExample.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/examples/AuthTlsExample.php b/modules/platforms/php/examples/AuthTlsExample.php
new file mode 100644
index 0000000..6f5fffc
--- /dev/null
+++ b/modules/platforms/php/examples/AuthTlsExample.php
@@ -0,0 +1,129 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once __DIR__ . '/../vendor/autoload.php';
+
+use Apache\Ignite\Client;
+use Apache\Ignite\ClientConfiguration;
+use Apache\Ignite\Cache\CacheInterface;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Type\ObjectType;
+
+// This example demonstrates how to establish a secure connection to an Ignite node and use username/password authentication,
+// as well as basic Key-Value Queries operations for primitive types:
+// - connects to a node using TLS and providing username/password
+// - creates a cache, if it doesn't exist
+// - specifies key and value type of the cache
+// - put data of primitive types into the cache
+// - get data from the cache
+// - destroys the cache
+class AuthTlsExample
+{
+ const ENDPOINT = 'localhost:10800';
+ const USER_NAME = 'ignite';
+ const PASSWORD = 'ignite';
+
+ const TLS_CLIENT_CERT_FILE_NAME = __DIR__ . '/certs/client.pem';
+ const TLS_CA_FILE_NAME = __DIR__ . '/certs/ca.pem';
+
+ const CACHE_NAME = 'AuthTlsExample_cache';
+
+ public function start(): void
+ {
+ $client = new Client();
+ try {
+ $tlsOptions = [
+ 'local_cert' => AuthTlsExample::TLS_CLIENT_CERT_FILE_NAME,
+ 'cafile' => AuthTlsExample::TLS_CA_FILE_NAME
+ ];
+
+ $config = (new ClientConfiguration(AuthTlsExample::ENDPOINT))->
+ setUserName(AuthTlsExample::USER_NAME)->
+ setPassword(AuthTlsExample::PASSWORD)->
+ setTLSOptions($tlsOptions);
+
+ $client->connect($config);
+
+ echo("Client connected successfully (with TLS and authentication enabled)" . PHP_EOL);
+
+ $cache = $client->getOrCreateCache(AuthTlsExample::CACHE_NAME)->
+ setKeyType(ObjectType::BYTE)->
+ setValueType(ObjectType::SHORT_ARRAY);
+
+ $this->putGetData($cache);
+ $client->destroyCache(AuthTlsExample::CACHE_NAME);
+ } catch (ClientException $e) {
+ echo('ERROR: ' . $e->getMessage() . PHP_EOL);
+ } finally {
+ $client->disconnect();
+ }
+ }
+
+ private function putGetData(CacheInterface $cache): void
+ {
+ $values = [
+ 1 => $this->generateValue(1),
+ 2 => $this->generateValue(2),
+ 3 => $this->generateValue(3)
+ ];
+
+ // put values
+ foreach ($values as $key => $value) {
+ $cache->put($key, $value);
+ }
+ echo('Cache values put successfully:' . PHP_EOL);
+ foreach ($values as $key => $value) {
+ $this->printValue($key, $value);
+ }
+
+ // get and compare values
+ echo('Cache values get:' . PHP_EOL);
+ foreach ($values as $key => $value) {
+ $cacheValue = $cache->get($key);
+ $this->printValue($key, $cacheValue);
+ if (!$this->compareValues($value, $cacheValue)) {
+ echo('Unexpected cache value!' . PHP_EOL);
+ return;
+ }
+ }
+ echo('Cache values compared successfully' . PHP_EOL);
+ }
+
+ private function compareValues(array $array1, array $array2): bool
+ {
+ return count(array_diff($array1, $array2)) === 0;
+ }
+
+ private function generateValue(int $key): array
+ {
+ $length = $key + 2;
+ $result = [];
+ for ($i = 0; $i < $length; $i++) {
+ array_push($result, $key * 10 + $i);
+ }
+ return $result;
+ }
+
+ private function printValue($key, $value): void
+ {
+ echo(sprintf(' %d => [%s]%s', $key, implode(', ', $value), PHP_EOL));
+ }
+}
+
+$authTlsExample = new AuthTlsExample();
+$authTlsExample->start();
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/examples/CachePutGetExample.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/examples/CachePutGetExample.php b/modules/platforms/php/examples/CachePutGetExample.php
new file mode 100644
index 0000000..4d9db53
--- /dev/null
+++ b/modules/platforms/php/examples/CachePutGetExample.php
@@ -0,0 +1,184 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once __DIR__ . '/../vendor/autoload.php';
+
+use Apache\Ignite\Client;
+use Apache\Ignite\ClientConfiguration;
+use Apache\Ignite\Cache\CacheEntry;
+use Apache\Ignite\Query\ScanQuery;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Data\BinaryObject;
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Type\ComplexObjectType;
+
+class Person
+{
+ private static $personId = 0;
+
+ public $id;
+ public $firstName;
+ public $lastName;
+ public $salary;
+
+ public function __construct(string $firstName = null, string $lastName = null, float $salary = 0)
+ {
+ $this->id = Person::generateId();
+ $this->firstName = $firstName;
+ $this->lastName = $lastName;
+ $this->salary = $salary;
+ }
+
+ public function printObject(): void
+ {
+ echo(sprintf(' %s%s', Person::class, PHP_EOL));
+ Person::printField('id', $this->id);
+ Person::printField('firstName', $this->firstName);
+ Person::printField('lastName', $this->lastName);
+ Person::printField('salary', $this->salary);
+ }
+
+ public static function generateId(): int
+ {
+ $id = Person::$personId;
+ Person::$personId++;
+ return $id;
+ }
+
+ public static function printField(string $fieldName, $fieldValue): void
+ {
+ echo(sprintf(' %s : %s%s', $fieldName, $fieldValue, PHP_EOL));
+ }
+}
+
+// This example demonstrates basic Cache, Key-Value Queries and Scan Query operations:
+// - connects to a node
+// - creates a cache, if it doesn't exist
+// - specifies key type as Integer
+// - executes different cache operations with Complex Objects and Binary Objects
+// - put several objects
+// - putAll
+// - get
+// - getAll
+// - ScanQuery
+// - destroys the cache
+class CachePutGetExample
+{
+ const ENDPOINT = '127.0.0.1:10800';
+ const CACHE_NAME = 'CachePutGetExample_person';
+
+ private $personCache;
+ private $binaryObjectCache;
+ private $personObjectType;
+
+ public function start(): void
+ {
+ $client = new Client();
+ try {
+ $client->connect(new ClientConfiguration(CachePutGetExample::ENDPOINT));
+
+ $this->personObjectType = (new ComplexObjectType())->
+ setFieldType('id', ObjectType::INTEGER);
+
+ $this->personCache = $client->getOrCreateCache(CachePutGetExample::CACHE_NAME)->
+ setKeyType(ObjectType::INTEGER)->
+ setValueType($this->personObjectType);
+
+ $this->binaryObjectCache = $client->getCache(CachePutGetExample::CACHE_NAME)->
+ setKeyType(ObjectType::INTEGER);
+
+ $this->putComplexObjects();
+ $this->putAllBinaryObjects();
+
+ $this->getAllComplexObjects();
+ $this->getBinaryObjects();
+
+ $this->scanQuery();
+
+ $client->destroyCache(CachePutGetExample::CACHE_NAME);
+ } catch (ClientException $e) {
+ echo('ERROR: ' . $e->getMessage() . PHP_EOL);
+ } finally {
+ $client->disconnect();
+ }
+ }
+
+ private function putComplexObjects(): void
+ {
+ $person1 = new Person('John', 'Doe', 1000);
+ $person2 = new Person('Jane', 'Roe', 2000);
+
+ $this->personCache->put($person1->id, $person1);
+ $this->personCache->put($person2->id, $person2);
+
+ echo('Complex Objects put successfully' . PHP_EOL);
+ }
+
+ private function putAllBinaryObjects(): void
+ {
+ // create binary object from scratch
+ $personBinaryObject1 = (new BinaryObject(Person::class))->
+ setField('id', Person::generateId(), ObjectType::INTEGER)->
+ setField('firstName', 'Mary')->
+ setField('lastName', 'Major')->
+ setField('salary', 1500, ObjectType::DOUBLE);
+
+ // create binary object from complex object
+ $personBinaryObject2 = BinaryObject::fromObject(
+ new Person('Richard', 'Miles', 800), $this->personObjectType);
+
+ $this->binaryObjectCache->putAll([
+ new CacheEntry($personBinaryObject1->getField('id'), $personBinaryObject1),
+ new CacheEntry($personBinaryObject2->getField('id'), $personBinaryObject2)
+ ]);
+
+ echo('Binary Objects put successfully using putAll()' . PHP_EOL);
+ }
+
+ private function getAllComplexObjects(): void
+ {
+ $persons = $this->personCache->getAll([0, 1]);
+ echo('Complex Objects getAll:' . PHP_EOL);
+ foreach ($persons as $person) {
+ $person->getValue()->printObject();
+ }
+ }
+
+ private function getBinaryObjects(): void
+ {
+ $personBinaryObject = $this->binaryObjectCache->get(2);
+ echo('Binary Object get:' . PHP_EOL);
+ echo(sprintf(" %s%s", $personBinaryObject->getTypeName(), PHP_EOL));
+ foreach ($personBinaryObject->getFieldNames() as $fieldName) {
+ $fieldValue = $personBinaryObject->getField($fieldName);
+ Person::printField($fieldName, $fieldValue);
+ }
+ }
+
+ private function scanQuery(): void
+ {
+ $cursor = $this->personCache->query(new ScanQuery());
+ echo('Scan query results:' . PHP_EOL);
+ foreach ($cursor as $cacheEntry) {
+ $cacheEntry->getValue()->printObject();
+ }
+ }
+}
+
+$cachePutGetExample = new CachePutGetExample();
+$cachePutGetExample->start();
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/examples/FailoverExample.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/examples/FailoverExample.php b/modules/platforms/php/examples/FailoverExample.php
new file mode 100644
index 0000000..7598511
--- /dev/null
+++ b/modules/platforms/php/examples/FailoverExample.php
@@ -0,0 +1,67 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once __DIR__ . '/../vendor/autoload.php';
+
+use Apache\Ignite\Client;
+use Apache\Ignite\ClientConfiguration;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Exception\NoConnectionException;
+use Apache\Ignite\Exception\OperationStatusUnknownException;
+
+const ENDPOINT1 = 'localhost:10800';
+const ENDPOINT2 = 'localhost:10801';
+const ENDPOINT3 = 'localhost:10802';
+
+const CACHE_NAME = 'test_cache';
+
+// This example demonstrates failover behavior of the client
+// - configures the client to connect to a set of nodes
+// - connects to a node
+// - executes an operation with Ignite server in a cycle (10 operations with 5 seconds pause) and finishes
+// - if connection is broken, the client automatically tries to reconnect to another node
+// - if not possible to connect to any nodes, the example finishes
+function connectClient() {
+ $client = new Client();
+ $client->setDebug(true);
+ try {
+ $clientConfiguration = new ClientConfiguration(ENDPOINT1, ENDPOINT2, ENDPOINT3);
+ // connect to Ignite node
+ $client->connect($clientConfiguration);
+ echo("Client connected successfully" . PHP_EOL);
+ for ($i = 0; $i < 10; $i++) {
+ try {
+ $client->getOrCreateCache(CACHE_NAME);
+ sleep(5);
+ } catch (OperationStatusUnknownException $e) {
+ // Status of the operation is unknown,
+ // a real application may repeat the operation if necessary
+ }
+ }
+ } catch (NoConnectionException $e) {
+ // The client is disconnected, all further operation with Ignite server fail till the client is connected again.
+ // A real application may recall $client->connect() with the same or different list of Ignite nodes.
+ echo('ERROR: ' . $e->getMessage() . PHP_EOL);
+ } catch (ClientException $e) {
+ echo('ERROR: ' . $e->getMessage() . PHP_EOL);
+ } finally {
+ $client->disconnect();
+ }
+}
+
+connectClient();
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/examples/SqlExample.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/examples/SqlExample.php b/modules/platforms/php/examples/SqlExample.php
new file mode 100644
index 0000000..db0baf6
--- /dev/null
+++ b/modules/platforms/php/examples/SqlExample.php
@@ -0,0 +1,237 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once __DIR__ . '/../vendor/autoload.php';
+
+use Apache\Ignite\Client;
+use Apache\Ignite\ClientConfiguration;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Cache\CacheInterface;
+use Apache\Ignite\Cache\CacheConfiguration;
+use Apache\Ignite\Query\SqlFieldsQuery;
+
+// This example shows primary APIs to use with Ignite as with an SQL database:
+// - connects to a node
+// - creates a cache, if it doesn't exist
+// - creates tables (CREATE TABLE)
+// - creates indices (CREATE INDEX)
+// - writes data of primitive types into the tables (INSERT INTO table)
+// - reads data from the tables (SELECT ...)
+// - deletes tables (DROP TABLE)
+// - destroys the cache
+class SqlExample {
+ const ENDPOINT = '127.0.0.1:10800';
+
+ const COUNTRY_CACHE_NAME = 'Country';
+ const CITY_CACHE_NAME = 'City';
+ const COUNTRY_LANGUAGE_CACHE_NAME = 'CountryLng';
+ const DUMMY_CACHE_NAME = 'SqlExample_Dummy';
+
+ public function start(): void
+ {
+ $client = new Client();
+ try {
+ $client->connect(new ClientConfiguration(SqlExample::ENDPOINT));
+
+ $cache = $client->getOrCreateCache(
+ SqlExample::DUMMY_CACHE_NAME,
+ (new CacheConfiguration())->setSqlSchema('PUBLIC'));
+
+ $this->createDatabaseObjects($cache);
+ $this->insertData($cache);
+
+ $countryCache = $client->getCache(SqlExample::COUNTRY_CACHE_NAME);
+ $cityCache = $client->getCache(SqlExample::CITY_CACHE_NAME);
+
+ $this->getMostPopulatedCities($countryCache);
+ $this->getTopCitiesInThreeCountries($cityCache);
+ $this->getCityDetails($cityCache, 5);
+
+ $this->deleteDatabaseObjects($cache);
+ $client->destroyCache(SqlExample::DUMMY_CACHE_NAME);
+ } catch (ClientException $e) {
+ echo('ERROR: ' . $e->getMessage() . PHP_EOL);
+ } finally {
+ $client->disconnect();
+ }
+ }
+
+ public function createDatabaseObjects(CacheInterface $cache): void
+ {
+ $createCountryTable = 'CREATE TABLE Country (' .
+ 'Code CHAR(3) PRIMARY KEY,' .
+ 'Name CHAR(52),' .
+ 'Continent CHAR(50),' .
+ 'Region CHAR(26),' .
+ 'SurfaceArea DECIMAL(10,2),' .
+ 'IndepYear SMALLINT(6),' .
+ 'Population INT(11),' .
+ 'LifeExpectancy DECIMAL(3,1),' .
+ 'GNP DECIMAL(10,2),' .
+ 'GNPOld DECIMAL(10,2),' .
+ 'LocalName CHAR(45),' .
+ 'GovernmentForm CHAR(45),' .
+ 'HeadOfState CHAR(60),' .
+ 'Capital INT(11),' .
+ 'Code2 CHAR(2)' .
+ ') WITH "template=partitioned, backups=1, CACHE_NAME=' . SqlExample::COUNTRY_CACHE_NAME . '"';
+
+ $createCityTable = 'CREATE TABLE City (' .
+ 'ID INT(11),' .
+ 'Name CHAR(35),' .
+ 'CountryCode CHAR(3),' .
+ 'District CHAR(20),' .
+ 'Population INT(11),' .
+ 'PRIMARY KEY (ID, CountryCode)' .
+ ') WITH "template=partitioned, backups=1, affinityKey=CountryCode, CACHE_NAME=' . SqlExample::CITY_CACHE_NAME . '"';
+
+ $createCountryLanguageTable = 'CREATE TABLE CountryLanguage (' .
+ 'CountryCode CHAR(3),' .
+ 'Language CHAR(30),' .
+ 'IsOfficial CHAR(2),' .
+ 'Percentage DECIMAL(4,1),' .
+ 'PRIMARY KEY (CountryCode, Language)' .
+ ') WITH "template=partitioned, backups=1, affinityKey=CountryCode, CACHE_NAME=' . SqlExample::COUNTRY_LANGUAGE_CACHE_NAME . '"';
+
+ // create tables
+ $cache->query(new SqlFieldsQuery($createCountryTable))->getAll();
+ $cache->query(new SqlFieldsQuery($createCityTable))->getAll();
+ $cache->query(new SqlFieldsQuery($createCountryLanguageTable))->getAll();
+
+ // create indices
+ $cache->query(new SqlFieldsQuery(
+ 'CREATE INDEX idx_country_code ON city (CountryCode)'))->getAll();
+ $cache->query(new SqlFieldsQuery(
+ 'CREATE INDEX idx_lang_country_code ON CountryLanguage (CountryCode)'))->getAll();
+
+ echo('Database objects created' . PHP_EOL);
+ }
+
+ private function insertData(CacheInterface $cache): void
+ {
+ $cities = [
+ ['New York', 'USA', 'New York', 8008278],
+ ['Los Angeles', 'USA', 'California', 3694820],
+ ['Chicago', 'USA', 'Illinois', 2896016],
+ ['Houston', 'USA', 'Texas', 1953631],
+ ['Philadelphia', 'USA', 'Pennsylvania', 1517550],
+ ['Moscow', 'RUS', 'Moscow (City)', 8389200],
+ ['St Petersburg', 'RUS', 'Pietari', 4694000],
+ ['Novosibirsk', 'RUS', 'Novosibirsk', 1398800],
+ ['Nizni Novgorod', 'RUS', 'Nizni Novgorod', 1357000],
+ ['Jekaterinburg', 'RUS', 'Sverdlovsk', 1266300],
+ ['Shanghai', 'CHN', 'Shanghai', 9696300],
+ ['Peking', 'CHN', 'Peking', 7472000],
+ ['Chongqing', 'CHN', 'Chongqing', 6351600],
+ ['Tianjin', 'CHN', 'Tianjin', 5286800],
+ ['Wuhan', 'CHN', 'Hubei', 4344600]
+ ];
+
+ $cityQuery = new SqlFieldsQuery(
+ 'INSERT INTO City(ID, Name, CountryCode, District, Population) VALUES (?, ?, ?, ?, ?)');
+
+ for ($i = 0; $i < count($cities); $i++) {
+ $cache->query($cityQuery->setArgs($i, ...$cities[$i]))->getAll();
+ }
+
+ $countries = [
+ ['USA', 'United States', 'North America', 'North America',
+ 9363520.00, 1776, 278357000, 77.1, 8510700.00, 8110900.00,
+ 'United States', 'Federal Republic', 'George W. Bush', 3813, 'US'],
+ ['RUS', 'Russian Federation', 'Europe', 'Eastern Europe',
+ 17075400.00, 1991, 146934000, 67.2, 276608.00, 442989.00,
+ 'Rossija', 'Federal Republic', 'Vladimir Putin', 3580, 'RU'],
+ ['CHN', 'China', 'Asia', 'Eastern Asia',
+ 9572900.00, -1523, 1277558000, 71.4, 982268.00, 917719.00,
+ 'Zhongquo', 'PeoplesRepublic', 'Jiang Zemin', 1891, 'CN']
+ ];
+
+ $countryQuery = new SqlFieldsQuery('INSERT INTO Country(' .
+ 'Code, Name, Continent, Region, SurfaceArea,' .
+ 'IndepYear, Population, LifeExpectancy, GNP, GNPOld,' .
+ 'LocalName, GovernmentForm, HeadOfState, Capital, Code2)' .
+ 'VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
+
+ foreach ($countries as $country) {
+ $cache->query($countryQuery->setArgs(...$country))->getAll();
+ }
+
+ echo('Data are inserted' . PHP_EOL);
+ }
+
+ private function getMostPopulatedCities(CacheInterface $countryCache): void
+ {
+ $query = new SqlFieldsQuery(
+ 'SELECT name, population FROM City ORDER BY population DESC LIMIT 10');
+
+ $cursor = $countryCache->query($query);
+
+ echo('10 Most Populated Cities:' . PHP_EOL);
+
+ foreach ($cursor as $row) {
+ echo(sprintf(' %d people live in %s%s', $row[1], $row[0], PHP_EOL));
+ }
+ }
+
+ private function getTopCitiesInThreeCountries(CacheInterface $countryCache): void
+ {
+ $query = new SqlFieldsQuery(
+ "SELECT country.name, city.name, MAX(city.population) as max_pop FROM country
+ JOIN city ON city.countrycode = country.code
+ WHERE country.code IN ('USA','RUS','CHN')
+ GROUP BY country.name, city.name ORDER BY max_pop DESC LIMIT 3");
+
+ $cursor = $countryCache->query($query);
+
+ echo('3 Most Populated Cities in US, RUS and CHN:' . PHP_EOL);
+
+ foreach ($cursor->getAll() as $row) {
+ echo(sprintf(' %d people live in %s, %s%s', $row[2], $row[1], $row[0], PHP_EOL));
+ }
+ }
+
+ private function getCityDetails(CacheInterface $cityCache, int $cityId): void
+ {
+ $query = (new SqlFieldsQuery('SELECT * FROM City WHERE id = ?'))->
+ setArgs($cityId)->
+ setIncludeFieldNames(true);
+
+ $cursor = $cityCache->query($query);
+
+ $fieldNames = $cursor->getFieldNames();
+
+ foreach ($cursor->getAll() as $city) {
+ echo('City Info:' . PHP_EOL);
+ for ($i = 0; $i < count($fieldNames); $i++) {
+ echo(sprintf(' %s : %s%s', $fieldNames[$i], $city[$i], PHP_EOL));
+ }
+ }
+ }
+
+ private function deleteDatabaseObjects($cache): void
+ {
+ $cache->query(new SqlFieldsQuery('DROP TABLE IF EXISTS Country'))->getAll();
+ $cache->query(new SqlFieldsQuery('DROP TABLE IF EXISTS City'))->getAll();
+ $cache->query(new SqlFieldsQuery('DROP TABLE IF EXISTS CountryLanguage'))->getAll();
+
+ echo('Database objects dropped' . PHP_EOL);
+ }
+}
+
+$sqlExample = new SqlExample();
+$sqlExample->start();
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/examples/SqlQueryEntriesExample.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/examples/SqlQueryEntriesExample.php b/modules/platforms/php/examples/SqlQueryEntriesExample.php
new file mode 100644
index 0000000..a02733e
--- /dev/null
+++ b/modules/platforms/php/examples/SqlQueryEntriesExample.php
@@ -0,0 +1,127 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+require_once __DIR__ . '/../vendor/autoload.php';
+
+use Apache\Ignite\Client;
+use Apache\Ignite\ClientConfiguration;
+use Apache\Ignite\Cache\CacheConfiguration;
+use Apache\Ignite\Cache\QueryEntity;
+use Apache\Ignite\Cache\QueryField;
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Type\ComplexObjectType;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Query\SqlQuery;
+
+class Person
+{
+ private static $personId = 0;
+
+ public $id;
+ public $firstName;
+ public $lastName;
+ public $salary;
+
+ public function __construct(string $firstName = null, string $lastName = null, float $salary = 0)
+ {
+ $this->id = Person::generateId();
+ $this->firstName = $firstName;
+ $this->lastName = $lastName;
+ $this->salary = $salary;
+ }
+
+ public static function generateId(): int
+ {
+ $id = Person::$personId;
+ Person::$personId++;
+ return $id;
+ }
+}
+
+// This example demonstrates basic Cache, Key-Value Queries and SQL Query operations:
+// - connects to a node
+// - creates a cache from CacheConfiguration, if it doesn't exist
+// - writes data of primitive and Complex Object types into the cache using Key-Value put operation
+// - reads data from the cache using SQL Query
+// - destroys the cache
+class SqlQueryEntriesExample {
+ const ENDPOINT = '127.0.0.1:10800';
+ const PERSON_CACHE_NAME = 'SqlQueryEntriesExample_person';
+
+ private $cache;
+
+ public function start(): void
+ {
+ $client = new Client();
+ try {
+ $client->connect(new ClientConfiguration(self::ENDPOINT));
+
+ $cacheCfg = (new CacheConfiguration())->
+ setQueryEntities(
+ (new QueryEntity())->
+ setValueTypeName('Person')->
+ setFields(
+ new QueryField('id', 'java.lang.Integer'),
+ new QueryField('firstName', 'java.lang.String'),
+ new QueryField('lastName', 'java.lang.String'),
+ new QueryField('salary', 'java.lang.Double')
+ ));
+ $this->cache = $client->getOrCreateCache(self::PERSON_CACHE_NAME, $cacheCfg)->
+ setKeyType(ObjectType::INTEGER)->
+ setValueType((new ComplexObjectType())->
+ setFieldType('id', ObjectType::INTEGER));
+
+ $this->generateData();
+
+ $sqlCursor = $this->cache->query(
+ (new SqlQuery('Person', 'salary > ? and salary <= ?'))->
+ setArgs(900.0, 1600.0));
+
+ echo('SqlQuery results (salary between 900 and 1600):' . PHP_EOL);
+ foreach ($sqlCursor as $cacheEntry) {
+ $person = $cacheEntry->getValue();
+ echo(sprintf(' name: %s %s, salary: %.2f %s',
+ $person->firstName, $person->lastName, $person->salary, PHP_EOL));
+ }
+
+ $client->destroyCache(self::PERSON_CACHE_NAME);
+ } catch (ClientException $e) {
+ echo('ERROR: ' . $e->getMessage() . PHP_EOL);
+ } finally {
+ $client->disconnect();
+ }
+ }
+
+ private function generateData(): void
+ {
+ $persons = [
+ ['John', 'Doe', 1000.0],
+ ['Jane', 'Roe', 2000.0],
+ ['Mary', 'Major', 1500.0],
+ ['Richard', 'Miles', 800.0]
+ ];
+ foreach ($persons as $data) {
+ $person = new Person(...$data);
+ $this->cache->put($person->id, $person);
+ }
+ echo('Data is generated' . PHP_EOL);
+ }
+}
+
+$sqlQueryEntriesExample = new SqlQueryEntriesExample();
+$sqlQueryEntriesExample->start();
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/examples/certs/ca.pem
----------------------------------------------------------------------
diff --git a/modules/platforms/php/examples/certs/ca.pem b/modules/platforms/php/examples/certs/ca.pem
new file mode 100644
index 0000000..ba90793
--- /dev/null
+++ b/modules/platforms/php/examples/certs/ca.pem
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFfzCCA2egAwIBAgIJAIH05meRt7kjMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
+BAYTAkZSMQowCAYDVQQIDAEuMQowCAYDVQQHDAEuMSMwIQYDVQQKDBpBQ01FIFNp
+Z25pbmcgQXV0aG9yaXR5IEluYzEKMAgGA1UEAwwBLjAeFw0xODA0MTIyMDUxMDFa
+Fw0yODA0MDkyMDUxMDFaMFYxCzAJBgNVBAYTAkZSMQowCAYDVQQIDAEuMQowCAYD
+VQQHDAEuMSMwIQYDVQQKDBpBQ01FIFNpZ25pbmcgQXV0aG9yaXR5IEluYzEKMAgG
+A1UEAwwBLjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMoilf6lWZt8
+F+QkZj2zW8PTEiOzqjLDCmEhnoVOPXAbCucaHuqQfK8xHL2FjlkeRWO1egzXBQ/V
+K+p2+ck/1D98qL8gYfR8Zf1WUUkgBYjnch9r+BPqIjSwBD8e3HyTIq+DGQ8tYqh0
+1GtP6tooZYF2VBKu7aY69vOOgM16k+2GLR7ILz5MtHARNshu/YYWU8GgIIKXVK8e
+DJU1swVhzCWDxX8S9BNuT13WoajOk6GhTkbKIQs0e32arHVfTV0G5s/FlAjtze4r
+kWsK+W/IJky98QLZqdHfoXxlPD4Ir6wuRjIZWfuliLmud5umhRdfT18vtApOiPR/
+nxFdITM914MubR6p0jEvnbF2PCQTKQVsGqpPRrsnqQwsLGUJKOGlS+Njwv6zUvJq
+xH5AjJcPNnwhc3dwcWoiYgswCcttUWz/a9h2SI5zggfyC3aVl72WmcsDbNgsAIJr
+ML5d5EIr+RvbTzQEaqLOHj1q8rysrRx8+HdtKRjXTJsTqpqCkAm+UWnLdlEnxvNW
+Asy0TZ65aGAR8ysyEO8s2xq0m2eTai1BPj91Yt3YnozWjvC0fdC6QL8Ksxka7HYO
+MYLXkwtlpi3m/dXVEk9Xd9SAE77+9aPN+MYAEvCG6WA2Drb7nOBVm31ATY20cEln
+I2YqiMBn05sjohacEww+7LVqYeez1xRvAgMBAAGjUDBOMB0GA1UdDgQWBBSy3uNf
+iwlv/7mjyiglCjKMq5kJDDAfBgNVHSMEGDAWgBSy3uNfiwlv/7mjyiglCjKMq5kJ
+DDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQACrOj3S0CpJVuCsgsZ
+JKCnPn0HVfJ0nU8tKMb43xq6r7V7GsUvdJIvzgiBC19ld+mWNUp25B9M9zOf1glL
+L9h2Tlu8gg+0DJ/1/ipZLNc36Q77Te8KECDKt8k9eI5N6HLS57mCZgE6CmGhc7zg
+notGQxzjfW8XQWDUwqwhfMZ9CjL+Tz7rHbvTCNrg9T0Ha57ajNxONlHsVUSMnbB6
+mN2n2pbpf40X4LL5j+mxxr0v6hfAF89U6hekeRf/8LMDApIc/6iVxGskwCOHZhkc
+w761WDHC4gh64cAWUni7YDJSCP8Djgdi34WQs4bk05f3u/86V702doR9JPJsRoQg
+P1juHur8vedjSQTqvA5TAt3ct6wkgVmeeqnIDTH2JFNCnssVWtJburOibUHgKvqe
+ZH0y3JF2eCcVXPPq6M6qM7W2IziArsZs22tkos2ARaDDU8ekmsEOH9SNphVICAet
+AT6b8YyOutTXO4LIN1TUeXmeKMpOAA2+YNCp+/OxbzkqvZxYuvbBtoSiIfrHyW4k
+rE0rRTYpB1Mk7R4+hwPnJim1OvZ+vLeLzvgGIyZKKiku2bp0YB8KGsAchnnJVlyo
+Oca/YSkKIBYCiQjxg5rX1/ZonhAkRbuqzmQdb9bJoGoN8kUdN9wvZHC3YPtox1Nd
+GoJSdO3MNkK5EwafrMAGh2Jmxg==
+-----END CERTIFICATE-----
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/examples/certs/client.pem
----------------------------------------------------------------------
diff --git a/modules/platforms/php/examples/certs/client.pem b/modules/platforms/php/examples/certs/client.pem
new file mode 100644
index 0000000..8016ff8
--- /dev/null
+++ b/modules/platforms/php/examples/certs/client.pem
@@ -0,0 +1,81 @@
+-----BEGIN CERTIFICATE-----
+MIIFJTCCAw0CAQEwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCRlIxCjAIBgNV
+BAgMAS4xCjAIBgNVBAcMAS4xIzAhBgNVBAoMGkFDTUUgU2lnbmluZyBBdXRob3Jp
+dHkgSW5jMQowCAYDVQQDDAEuMB4XDTE4MDQxMjIwNTEwNFoXDTI4MDQwOTIwNTEw
+NFowWzELMAkGA1UEBhMCRlIxCjAIBgNVBAgMAS4xCjAIBgNVBAcMAS4xIzAhBgNV
+BAoMGkFDTUUgU2lnbmluZyBBdXRob3JpdHkgSW5jMQ8wDQYDVQQDDAZDTElFTlQw
+ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCp1yTtzT01KDx6qyidy4GQ
+C/NbPcOkPHYYfTPkPy4xvdfPfx0FHBHxY5iqg7V2q5dbpVH1NOablC/sWOjwMXlQ
+Hs0M48Q0SRXgJA2a4wqKMfpJ6q8fxVbFENmm8d7YA3dXq6KxXq5yDxCy7pZk/ILP
+CbOobSHxA8NI0Dla9zMA12b6pdu2d0aK6fD98FdUU56Dn8re8YOlEEtRZmUZjIkt
+yoIP+RymKttz9opbSeY4gy/na9JziS2Ij6SVwnpdFIVvMXtux61WlIe9jy/JRWXL
+dmY8qz7ooTUofgV8wd+E9iTIYwJa26C8+AV1XGuI7aQHPSQwyRm0PGJaC4Bdutkf
+eeTu5KVxIQFgAUV2a7EYR9xiSiMW2DjCjTEShZkxs13jTG4tnr6KxUYCoNIy42XH
+WVmb7TKVkhpBKM+icqFRQ/0OhqZcYl1VKlYSutu7z32jGta+AgedMagV4sSzhHJf
+U8lBReZkFVo0Bh5wgZbmgwykW1YzqoMVxOZtaoF/4NyPfIo7icmI9SfM7Jbo/0zs
+CdWgetIPM8iEwXr4W1TjDRM6VLDnEMo77HUNHqJi9YQhIy0exsBdlfJnVpPGS3fj
+jA90qoUDoEFScDmAYsD8pyrSFkE13KBClUjQKn6KdNQfRxQApf972X7tqkMbX5KQ
+Np0GKuaTHt2xxirgJroeiQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQAT5wABZANT
+GUScEJo9NK2+nEVVCrf3YcirwB4uw2log/DamQnHeC2W7/YOQ+RAmqp0m4VX39pA
+jxUlQb546rBKL8mfzc88ReN/g/EoDEri1PKToGF+rntwtgpoj+ID2sK4kDyJRemJ
+d6lrNTIvB1zu6Ra6P5Y5Iq5swSZtigFkevwHfHACEs6EemWz8xsipBjOK+oX3sen
+N8t/KGiw0rsFXoXv/bKFaB3s9VcX8lbMG7FgPqlFCQnkEPqGSmoT8hNSqK1ZM3VK
+ueRkZVHaynZqoGIU1hglDWtObTUiz7Kgwv3MTbduoZE7hBzBSokn7aGjypdrTFuZ
+jrSKNe+sJePw7IfvuSo5Nnk5VNh26FS0C9EeeqCCAT1B/+u9M0DkmK6EPDUIly9f
+XjTlR04UaWf0EHgTroDY/KuDBR2ZKx344fr/52xZMDUoqNT2t/HW7cX2ff8vbsME
+IykmzSfVjE50gRAZMqAhDlWKR56VyuAwjpBBGAo7Zw3eyAQjVLYU0/f7/HONYchx
+wWPXCn1isRDFtzxx8WhuhtXUnSHgwnro+79W75mv9c6bkHoAH3pVbA9Wx4+hQv18
+V8SHa9CJn8absmNTSBGMXo+lFDDRnsjRDBCPElfkS5+ilvcJtfuqdtRvkR1ERil0
+N6gW1Y8iaVI7pfPeyWoM9GLTuvLmAYcuKQ==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAqdck7c09NSg8eqsoncuBkAvzWz3DpDx2GH0z5D8uMb3Xz38d
+BRwR8WOYqoO1dquXW6VR9TTmm5Qv7Fjo8DF5UB7NDOPENEkV4CQNmuMKijH6Seqv
+H8VWxRDZpvHe2AN3V6uisV6ucg8Qsu6WZPyCzwmzqG0h8QPDSNA5WvczANdm+qXb
+tndGiunw/fBXVFOeg5/K3vGDpRBLUWZlGYyJLcqCD/kcpirbc/aKW0nmOIMv52vS
+c4ktiI+klcJ6XRSFbzF7bsetVpSHvY8vyUVly3ZmPKs+6KE1KH4FfMHfhPYkyGMC
+WtugvPgFdVxriO2kBz0kMMkZtDxiWguAXbrZH3nk7uSlcSEBYAFFdmuxGEfcYkoj
+Ftg4wo0xEoWZMbNd40xuLZ6+isVGAqDSMuNlx1lZm+0ylZIaQSjPonKhUUP9Doam
+XGJdVSpWErrbu899oxrWvgIHnTGoFeLEs4RyX1PJQUXmZBVaNAYecIGW5oMMpFtW
+M6qDFcTmbWqBf+Dcj3yKO4nJiPUnzOyW6P9M7AnVoHrSDzPIhMF6+FtU4w0TOlSw
+5xDKO+x1DR6iYvWEISMtHsbAXZXyZ1aTxkt344wPdKqFA6BBUnA5gGLA/Kcq0hZB
+NdygQpVI0Cp+inTUH0cUAKX/e9l+7apDG1+SkDadBirmkx7dscYq4Ca6HokCAwEA
+AQKCAgAul8oWvtZKzfYBhREIcPrjRJQHdONGHBwdzcM9m6OVm8onr2yLqU621Sbd
+qHJQ0vQb/TeFuHSHO9kF0sJcmoX4V+rS3W1HFsG8ksd0tVJ/5QQP4SUX5zBNsbi0
+FuiWhCTqVTi1xg6/Vai0HcX+gFN2buftjbrg/rJFOHJzpRtF4NHsczHaVdBxbYpi
+b9vVU3dKDr09+i2uS9ENzLRxlN9RQ5v4u9ODNoCryHfeYWCaIkszBp5eecSXESkK
+uKaPAIE2pvGAy6Ce/vJaK3zlj3dEoP+dJzGD6i3GJQRmXF1wgYJHwvmzaUsobDY7
+IxaRIvh7z+csxw6ZJnOo1jzp+cd0a7iMSjz6BHjQuStnrTeUfFF9ZYyq3vV9vbKY
+5hvoeKuIj7LY/g5KV223vx5aojxiJFTgJ8DyJVYAC8LiMhF61Koua/S6WTpPR6Ga
+V56sF9JVqefVFGwOl4npK0TUUFqrHo8/grkxbO5KddgUU4CW4R/PK1jHDXo9d1pj
+fTD04kfBS6gAjEYdc+Va7YO1T72Ejjw0p0H5e/0xP/4j8xE6r/Kaq0nw3RppIY8d
+EuZDMRG/fvY/8/BakJr5xHZLIt7nLppP9rH4qZKVBylTy5P0kLcenDu6yYYBqUkt
+SAwOK4al/NYfAO4kgNa16uEmNexRmS6IVKUfZn0PJbbcTB/NnQKCAQEA0XR9GqiH
+VhI4td9qitxLSsM4lukLl1f2seJKsGGkyiJ7SgMXbpe5wmamPKT/8cYlcMD0gPjL
+jKZP5CQqTVuI2Zwsy6/KH3/UlCjVp7qOHeVcHLJs95JS+hiBqGK56shNpdRWoG/g
+7z3lnZuEFY5gfEWOjXGQOJIHp3b64njDAln31zjXNpHEpv0RPsmkUi1jNxpi1XDp
+J7M1ocoB22jn6voXxP6jvg48tQqz5FPN5fGr+WqkBPwcgtf2pN+weGAc4APrTxM2
+CsWk/aI2eGte1Ednk0Ci+RthgICS+cxj6cWgSQBnesbEH9+MOsn3Tp6rPGZ6FHsZ
+PSqnVMszXrvEtwKCAQEAz5UNaITyiw+ocOM8hgMnAg3C+whCTlts6NDJcjBLax5e
+uPCqYyMJmbB78mgmu5ZCB0CUcppxm73hGKiX+/wOPaAobJcqs+mG4YtmfgjZMYZQ
+s0C1gaZFc+mAXMFaR4Gqr9EXNtwh+zaHVUupAdATS0VZ2XSv4t2bDoeDZWnGPCZb
+9wfGMuorR8po8Fv8kH3G771DqZXSXbgVgsYUdIrchGYhPRaSyhvdGcRFootwEEjv
+PJ2S3E2uJQlZKlWAnQ5SGxKMWOWPSAGSK284pR9+HlvQpFD3SH1Ue5bAQWhRsVyW
+uMKnH0XpMOmYzUcXEKy1A41IbA9ZpoQoUbTZ+bp2vwKCAQEAvd3qyg+bHtrFrZgo
+7FdlqQ/ubF40s6x5ZCbNrbXVu6YmPKEwzH+dVCvY5YBswq3roppHCeJ+IbFhGl3u
+OtGO7DQ2Jy3i+0rVWLjrdHAYA+G17g2P2Zw6u5sbbZiRD9MjD/+7xxOjwztIueYP
+hbram8wxvOYE5kL5zUR9iG4P2EHV+LL94+mfagBdcZ0354ZdOcYhcXo44FQDefW0
+WUBvewHaKijqJY6iWTqqd3/AVYENc7rHk/01myZJ3osnXPdDNY5X8AZqJrmjJoe0
++NPb0nIn4cPl+ApqCCKFGQu+RltvQL2tEA6+GmZ6p5ANLqeGceozH/22k0vnA2Zv
+2qA7YQKCAQBnPde8WxsShMge1TXd5SV6hQOrvNDVje0d4fG/BDwOW716t9/WjK+S
+q88JojlZZQMT/k+WrC/C6O5SSE/G+PbQOZ7BW3HWp1f5R07Dcn0rf4UVkiJ0CBFU
+9BZui4/uLpSI+zJTi6qu+dDXYFj/WNCvyB9G4x0zdUpQMJ/uSWxZsC5fL5Oo8QRz
+oT0OBoIYDyZpSDWl26kUCaFROFkmGYZRp0Xyzw5UzQTrcs27aSRkRRIPkMNhJJVv
+QDYDsyDTfDLj2hbJg+r+QiHDzn5ayc39JWcgwlAq0oK5MSIPpeWzk7w2ykE6cZfo
+RtZDio7zMSKaUKNrczsAcYxoDs22wcGbAoIBAQCKlVIcL3e7exSFVRNORbnLosWh
+cYQquUZlxq6TkS14lJsGQ+pT02gAEpJktYEfiiBMG/mHXeaGQmMbAYgF7J79VcvN
+CJ1qZvvtSCSnWdMGlhs5zHzjCqk9sywtxRB8XJpp19cM7oTl4PU+ditoGTRlo0Ea
+cMuqdfg/SH/VExUyJzjyFKI5qKUnaTa83PZz4h0kt48oa4tlXzwBVKZYy/77qfQk
+ajH+THYPZ+32iDEVCpiJ9Cg8yTWGT7VxtgFRvEOBPY28T6zenl9Djl8omCOAz07a
+Ozq7QkTy4L0eCZrQ1BPHcmulHUuL+tZqKRukyBrtkTPanZEOHZ5RTfF32BVL
+-----END RSA PRIVATE KEY-----
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/examples/certs/keystore.jks
----------------------------------------------------------------------
diff --git a/modules/platforms/php/examples/certs/keystore.jks b/modules/platforms/php/examples/certs/keystore.jks
new file mode 100644
index 0000000..1da610f
Binary files /dev/null and b/modules/platforms/php/examples/certs/keystore.jks differ
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/examples/certs/truststore.jks
----------------------------------------------------------------------
diff --git a/modules/platforms/php/examples/certs/truststore.jks b/modules/platforms/php/examples/certs/truststore.jks
new file mode 100644
index 0000000..4d25cf7
Binary files /dev/null and b/modules/platforms/php/examples/certs/truststore.jks differ
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Cache/CacheConfiguration.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Cache/CacheConfiguration.php b/modules/platforms/php/src/Apache/Ignite/Cache/CacheConfiguration.php
new file mode 100644
index 0000000..e4a7ad6
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Cache/CacheConfiguration.php
@@ -0,0 +1,1011 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Cache;
+
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Type\ObjectArrayType;
+use Apache\Ignite\Type\ComplexObjectType;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+
+/**
+ * Class representing Ignite cache configuration on a server.
+ *
+ * All configuration settings are optional and have defaults which are defined on a server side.
+ *
+ * See Apache Ignite documentation for details of every configuration setting.
+ */
+class CacheConfiguration
+{
+ const PROP_NAME = 0;
+ const PROP_CACHE_MODE = 1;
+ const PROP_ATOMICITY_MODE = 2;
+ const PROP_BACKUPS = 3;
+ const PROP_WRITE_SYNCHRONIZATION_MODE = 4;
+ const PROP_COPY_ON_READ = 5;
+ const PROP_READ_FROM_BACKUP = 6;
+ const PROP_DATA_REGION_NAME = 100;
+ const PROP_IS_ONHEAP_CACHE_ENABLED = 101;
+ const PROP_QUERY_ENTITY = 200;
+ const PROP_QUERY_PARALLELISM = 201;
+ const PROP_QUERY_DETAIL_METRICS_SIZE = 202;
+ const PROP_SQL_SCHEMA = 203;
+ const PROP_SQL_INDEX_INLINE_MAX_SIZE = 204;
+ const PROP_SQL_ESCAPE_ALL = 205;
+ const PROP_MAX_QUERY_ITERATORS = 206;
+ const PROP_REBALANCE_MODE = 300;
+ const PROP_REBALANCE_DELAY = 301;
+ const PROP_REBALANCE_TIMEOUT = 302;
+ const PROP_REBALANCE_BATCH_SIZE = 303;
+ const PROP_REBALANCE_BATCHES_PREFETCH_COUNT = 304;
+ const PROP_REBALANCE_ORDER = 305;
+ const PROP_REBALANCE_THROTTLE = 306;
+ const PROP_GROUP_NAME = 400;
+ const PROP_CACHE_KEY_CONFIGURATION = 401;
+ const PROP_DEFAULT_LOCK_TIMEOUT = 402;
+ const PROP_MAX_CONCURRENT_ASYNC_OPS = 403;
+ const PROP_PARTITION_LOSS_POLICY = 404;
+ const PROP_EAGER_TTL = 405;
+ const PROP_STATISTICS_ENABLED = 406;
+
+ /** @name AtomicityMode
+ * @anchor AtomicityMode
+ * @{
+ */
+ const ATOMICITY_MODE_TRANSACTIONAL = 0;
+ const ATOMICITY_MODE_ATOMIC = 1;
+ /** @} */ // end of AtomicityMode
+
+ /** @name CacheMode
+ * @anchor CacheMode
+ * @{
+ */
+ const CACHE_MODE_LOCAL = 0;
+ const CACHE_MODE_REPLICATED = 1;
+ const CACHE_MODE_PARTITIONED = 2;
+ /** @} */ // end of CacheMode
+
+ /** @name PartitionLossPolicy
+ * @anchor PartitionLossPolicy
+ * @{
+ */
+ const PARTITION_LOSS_POLICY_READ_ONLY_SAFE = 0;
+ const PARTITION_LOSS_POLICY_READ_ONLY_ALL = 1;
+ const PARTITION_LOSS_POLICY_READ_WRITE_SAFE = 2;
+ const PARTITION_LOSS_POLICY_READ_WRITE_ALL = 3;
+ const PARTITION_LOSS_POLICY_IGNORE = 4;
+ /** @} */ // end of PartitionLossPolicy
+
+ /** @name RebalanceMode
+ * @anchor RebalanceMode
+ * @{
+ */
+ const REABALANCE_MODE_SYNC = 0;
+ const REABALANCE_MODE_ASYNC = 1;
+ const REABALANCE_MODE_NONE = 2;
+ /** @} */ // end of RebalanceMode
+
+ /** @name WriteSynchronizationMode
+ * @anchor WriteSynchronizationMode
+ * @{
+ */
+ const WRITE_SYNC_MODE_FULL_SYNC = 0;
+ const WRITE_SYNC_MODE_FULL_ASYNC = 1;
+ const WRITE_SYNC_MODE_PRIMARY_SYNC = 2;
+ /** @} */ // end of WriteSynchronizationMode
+
+ private $properties;
+ private static $propInfo;
+
+ /**
+ * Public CacheConfiguration constructor.
+ */
+ public function __construct()
+ {
+ $this->properties = [];
+ }
+
+ /**
+ *
+ *
+ * @param string $name
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setName(string $name): CacheConfiguration
+ {
+ $this->properties[self::PROP_NAME] = $name;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getName(): ?string
+ {
+ return $this->getProperty(self::PROP_NAME);
+ }
+
+ /**
+ *
+ *
+ * @param int $atomicityMode one of @ref AtomicityMode constants.
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ *
+ * @throws ClientException if error.
+ */
+ public function setAtomicityMode(int $atomicityMode): CacheConfiguration
+ {
+ ArgumentChecker::hasValueFrom(
+ $atomicityMode, 'atomicityMode', false, [self::ATOMICITY_MODE_TRANSACTIONAL, self::ATOMICITY_MODE_ATOMIC]);
+ $this->properties[self::PROP_ATOMICITY_MODE] = $atomicityMode;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int|null
+ */
+ public function getAtomicityMode(): ?int
+ {
+ return $this->getProperty(self::PROP_ATOMICITY_MODE);
+ }
+
+ /**
+ *
+ *
+ * @param int $backups
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setBackups(int $backups): CacheConfiguration
+ {
+ $this->properties[self::PROP_BACKUPS] = $backups;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int|null
+ */
+ public function getBackups(): ?int
+ {
+ return $this->getProperty(self::PROP_BACKUPS);
+ }
+
+ /**
+ *
+ *
+ * @param int $cacheMode one of @ref CacheMode constants.
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ *
+ * @throws ClientException if error.
+ */
+ public function setCacheMode(int $cacheMode): CacheConfiguration
+ {
+ ArgumentChecker::hasValueFrom(
+ $cacheMode,
+ 'cacheMode',
+ false,
+ [self::CACHE_MODE_LOCAL, self::CACHE_MODE_REPLICATED, self::CACHE_MODE_PARTITIONED]);
+ $this->properties[self::PROP_CACHE_MODE] = $cacheMode;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int|null
+ */
+ public function getCacheMode(): ?int
+ {
+ return $this->getProperty(self::PROP_CACHE_MODE);
+ }
+
+ /**
+ *
+ *
+ * @param bool $copyOnRead
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setCopyOnRead(bool $copyOnRead): CacheConfiguration
+ {
+ $this->properties[self::PROP_COPY_ON_READ] = $copyOnRead;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return bool|null
+ */
+ public function getCopyOnRead(): ?bool
+ {
+ return $this->getProperty(self::PROP_COPY_ON_READ);
+ }
+
+ /**
+ *
+ *
+ * @param string|null $dataRegionName
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setDataRegionName(?string $dataRegionName): CacheConfiguration
+ {
+ $this->properties[self::PROP_DATA_REGION_NAME] = $dataRegionName;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getDataRegionName(): ?string
+ {
+ return $this->getProperty(self::PROP_DATA_REGION_NAME);
+ }
+
+ /**
+ *
+ *
+ * @param bool $eagerTtl
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setEagerTtl(bool $eagerTtl): CacheConfiguration
+ {
+ $this->properties[self::PROP_EAGER_TTL] = $eagerTtl;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return bool|null
+ */
+ public function getEagerTtl(): ?bool
+ {
+ return $this->getProperty(self::PROP_EAGER_TTL);
+ }
+
+ /**
+ *
+ *
+ * @param bool $statisticsEnabled
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setStatisticsEnabled(bool $statisticsEnabled): CacheConfiguration
+ {
+ $this->properties[self::PROP_STATISTICS_ENABLED] = $statisticsEnabled;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return bool|null
+ */
+ public function getStatisticsEnabled(): ?bool
+ {
+ return $this->getProperty(self::PROP_STATISTICS_ENABLED);
+ }
+
+ /**
+ *
+ *
+ * @param string|null $groupName
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setGroupName(?string $groupName): CacheConfiguration
+ {
+ $this->properties[self::PROP_GROUP_NAME] = $groupName;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getGroupName(): ?string
+ {
+ return $this->getProperty(self::PROP_GROUP_NAME);
+ }
+
+ /**
+ *
+ *
+ * @param float $lockTimeout
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setDefaultLockTimeout(float $lockTimeout): CacheConfiguration
+ {
+ $this->properties[self::PROP_DEFAULT_LOCK_TIMEOUT] = $lockTimeout;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return float|null
+ */
+ public function getDefaultLockTimeout(): ?float
+ {
+ return $this->getProperty(self::PROP_DEFAULT_LOCK_TIMEOUT);
+ }
+
+ /**
+ *
+ *
+ * @param int $maxConcurrentAsyncOperations
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setMaxConcurrentAsyncOperations(int $maxConcurrentAsyncOperations): CacheConfiguration
+ {
+ $this->properties[self::PROP_MAX_CONCURRENT_ASYNC_OPS] = $maxConcurrentAsyncOperations;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int|null
+ */
+ public function getMaxConcurrentAsyncOperations(): ?int
+ {
+ return $this->getProperty(self::PROP_MAX_CONCURRENT_ASYNC_OPS);
+ }
+
+ /**
+ *
+ *
+ * @param int $maxQueryIterators
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setMaxQueryIterators(int $maxQueryIterators): CacheConfiguration
+ {
+ $this->properties[self::PROP_MAX_QUERY_ITERATORS] = $maxQueryIterators;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int|null
+ */
+ public function getMaxQueryIterators(): ?int
+ {
+ return $this->getProperty(self::PROP_MAX_QUERY_ITERATORS);
+ }
+
+ /**
+ *
+ *
+ * @param bool $isOnheapCacheEnabled
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setIsOnheapCacheEnabled(bool $isOnheapCacheEnabled): CacheConfiguration
+ {
+ $this->properties[self::PROP_IS_ONHEAP_CACHE_ENABLED] = $isOnheapCacheEnabled;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return bool|null
+ */
+ public function getIsOnheapCacheEnabled(): ?bool
+ {
+ return $this->getProperty(self::PROP_IS_ONHEAP_CACHE_ENABLED);
+ }
+
+ /**
+ *
+ *
+ * @param int $partitionLossPolicy one of @ref PartitionLossPolicy constants.
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ *
+ * @throws ClientException if error.
+ */
+ public function setPartitionLossPolicy(int $partitionLossPolicy): CacheConfiguration
+ {
+ ArgumentChecker::hasValueFrom(
+ $partitionLossPolicy,
+ 'partitionLossPolicy',
+ false,
+ [
+ self::PARTITION_LOSS_POLICY_READ_ONLY_SAFE,
+ self::PARTITION_LOSS_POLICY_READ_ONLY_ALL,
+ self::PARTITION_LOSS_POLICY_READ_WRITE_SAFE,
+ self::PARTITION_LOSS_POLICY_READ_WRITE_ALL,
+ self::PARTITION_LOSS_POLICY_IGNORE
+ ]);
+ $this->properties[self::PROP_PARTITION_LOSS_POLICY] = $partitionLossPolicy;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int|null
+ */
+ public function getPartitionLossPolicy(): ?int
+ {
+ return $this->getProperty(self::PROP_PARTITION_LOSS_POLICY);
+ }
+
+ /**
+ *
+ *
+ * @param int $queryDetailMetricsSize
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setQueryDetailMetricsSize(int $queryDetailMetricsSize): CacheConfiguration
+ {
+ $this->properties[self::PROP_QUERY_DETAIL_METRICS_SIZE] = $queryDetailMetricsSize;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int|null
+ */
+ public function getQueryDetailMetricsSize(): ?int
+ {
+ return $this->getProperty(self::PROP_QUERY_DETAIL_METRICS_SIZE);
+ }
+
+ /**
+ *
+ *
+ * @param int $queryParallelism
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setQueryParallelism(int $queryParallelism): CacheConfiguration
+ {
+ $this->properties[self::PROP_QUERY_PARALLELISM] = $queryParallelism;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int|null
+ */
+ public function getQueryParallelism(): ?int
+ {
+ return $this->getProperty(self::PROP_QUERY_PARALLELISM);
+ }
+
+ /**
+ *
+ *
+ * @param bool $readFromBackup
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setReadFromBackup(bool $readFromBackup): CacheConfiguration
+ {
+ $this->properties[self::PROP_READ_FROM_BACKUP] = $readFromBackup;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return bool|null
+ */
+ public function getReadFromBackup(): ?bool
+ {
+ return $this->getProperty(self::PROP_READ_FROM_BACKUP);
+ }
+
+ /**
+ *
+ *
+ * @param int $rebalanceBatchSize
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setRebalanceBatchSize(int $rebalanceBatchSize): CacheConfiguration
+ {
+ $this->properties[self::PROP_REBALANCE_BATCH_SIZE] = $rebalanceBatchSize;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int|null
+ */
+ public function getRebalanceBatchSize(): ?int
+ {
+ return $this->getProperty(self::PROP_REBALANCE_BATCH_SIZE);
+ }
+
+ /**
+ *
+ *
+ * @param float $rebalanceBatchesPrefetchCount
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setRebalanceBatchesPrefetchCount(float $rebalanceBatchesPrefetchCount): CacheConfiguration
+ {
+ $this->properties[self::PROP_REBALANCE_BATCHES_PREFETCH_COUNT] = $rebalanceBatchesPrefetchCount;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return float|null
+ */
+ public function getRebalanceBatchesPrefetchCount(): ?float
+ {
+ return $this->getProperty(self::PROP_REBALANCE_BATCHES_PREFETCH_COUNT);
+ }
+
+ /**
+ *
+ *
+ * @param float $rebalanceDelay
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setRebalanceDelay(float $rebalanceDelay): CacheConfiguration
+ {
+ $this->properties[self::PROP_REBALANCE_DELAY] = $rebalanceDelay;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return float|null
+ */
+ public function getRebalanceDelay(): ?float
+ {
+ return $this->getProperty(self::PROP_REBALANCE_DELAY);
+ }
+
+ /**
+ *
+ *
+ * @param int $rebalanceMode one of @ref RebalanceMode constants.
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ *
+ * @throws ClientException if error.
+ */
+ public function setRebalanceMode(int $rebalanceMode): CacheConfiguration
+ {
+ ArgumentChecker::hasValueFrom(
+ $rebalanceMode,
+ 'rebalanceMode',
+ false,
+ [self::REABALANCE_MODE_SYNC, self::REABALANCE_MODE_ASYNC, self::REABALANCE_MODE_NONE]);
+ $this->properties[self::PROP_REBALANCE_MODE] = $rebalanceMode;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int|null
+ */
+ public function getRebalanceMode(): ?int
+ {
+ return $this->getProperty(self::PROP_REBALANCE_MODE);
+ }
+
+ /**
+ *
+ *
+ * @param int $rebalanceOrder
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setRebalanceOrder(int $rebalanceOrder): CacheConfiguration
+ {
+ $this->properties[self::PROP_REBALANCE_ORDER] = $rebalanceOrder;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int|null
+ */
+ public function getRebalanceOrder(): ?int
+ {
+ return $this->getProperty(self::PROP_REBALANCE_ORDER);
+ }
+
+ /**
+ *
+ *
+ * @param float $rebalanceThrottle
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setRebalanceThrottle(float $rebalanceThrottle): CacheConfiguration
+ {
+ $this->properties[self::PROP_REBALANCE_THROTTLE] = $rebalanceThrottle;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return float|null
+ */
+ public function getRebalanceThrottle(): ?float
+ {
+ return $this->getProperty(self::PROP_REBALANCE_THROTTLE);
+ }
+
+ /**
+ *
+ *
+ * @param float $rebalanceTimeout
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setRebalanceTimeout(float $rebalanceTimeout): CacheConfiguration
+ {
+ $this->properties[self::PROP_REBALANCE_TIMEOUT] = $rebalanceTimeout;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return float|null
+ */
+ public function getRebalanceTimeout(): ?float
+ {
+ return $this->getProperty(self::PROP_REBALANCE_TIMEOUT);
+ }
+
+ /**
+ *
+ *
+ * @param bool $sqlEscapeAll
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setSqlEscapeAll(bool $sqlEscapeAll): CacheConfiguration
+ {
+ $this->properties[self::PROP_SQL_ESCAPE_ALL] = $sqlEscapeAll;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return bool|null
+ */
+ public function getSqlEscapeAll(): ?bool
+ {
+ return $this->getProperty(self::PROP_SQL_ESCAPE_ALL);
+ }
+
+ /**
+ *
+ *
+ * @param int $sqlIndexInlineMaxSize
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setSqlIndexInlineMaxSize(int $sqlIndexInlineMaxSize): CacheConfiguration
+ {
+ $this->properties[self::PROP_SQL_INDEX_INLINE_MAX_SIZE] = $sqlIndexInlineMaxSize;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int|null
+ */
+ public function getSqlIndexInlineMaxSize(): ?int
+ {
+ return $this->getProperty(self::PROP_SQL_INDEX_INLINE_MAX_SIZE);
+ }
+
+ /**
+ *
+ *
+ * @param string|null $sqlSchema
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setSqlSchema(?string $sqlSchema): CacheConfiguration
+ {
+ $this->properties[self::PROP_SQL_SCHEMA] = $sqlSchema;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getSqlSchema(): ?string
+ {
+ return $this->getProperty(self::PROP_SQL_SCHEMA);
+ }
+
+ /**
+ *
+ *
+ * @param int $writeSynchronizationMode one of @ref WriteSynchronizationMode constants.
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ *
+ * @throws ClientException if error.
+ */
+ public function setWriteSynchronizationMode(int $writeSynchronizationMode): CacheConfiguration
+ {
+ ArgumentChecker::hasValueFrom(
+ $writeSynchronizationMode,
+ 'writeSynchronizationMode',
+ false,
+ [self::WRITE_SYNC_MODE_FULL_SYNC, self::WRITE_SYNC_MODE_FULL_ASYNC, self::WRITE_SYNC_MODE_PRIMARY_SYNC]);
+ $this->properties[self::PROP_WRITE_SYNCHRONIZATION_MODE] = $writeSynchronizationMode;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int|null
+ */
+ public function getWriteSynchronizationMode(): ?int
+ {
+ return $this->getProperty(self::PROP_WRITE_SYNCHRONIZATION_MODE);
+ }
+
+ /**
+ *
+ *
+ * @param CacheKeyConfiguration ...$keyConfigurations
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setKeyConfigurations(CacheKeyConfiguration ...$keyConfigurations): CacheConfiguration
+ {
+ $this->properties[self::PROP_CACHE_KEY_CONFIGURATION] = $keyConfigurations;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return CacheKeyConfiguration[]|null
+ */
+ public function getKeyConfigurations(): ?array
+ {
+ return $this->getProperty(self::PROP_CACHE_KEY_CONFIGURATION);
+ }
+
+ /**
+ *
+ *
+ * @param QueryEntity ...$queryEntities
+ *
+ * @return CacheConfiguration the same instance of the CacheConfiguration.
+ */
+ public function setQueryEntities(QueryEntity ...$queryEntities): CacheConfiguration
+ {
+ $this->properties[self::PROP_QUERY_ENTITY] = $queryEntities;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return QueryEntity[]|null
+ */
+ public function getQueryEntities(): ?array
+ {
+ return $this->getProperty(self::PROP_QUERY_ENTITY);
+ }
+
+ private function getProperty(int $prop)
+ {
+ if (array_key_exists($prop, $this->properties)) {
+ return $this->properties[$prop];
+ }
+ return null;
+ }
+
+ static function init(): void
+ {
+ self::$propInfo = array(
+ self::PROP_NAME => ObjectType::STRING,
+ self::PROP_CACHE_MODE => ObjectType::INTEGER,
+ self::PROP_ATOMICITY_MODE => ObjectType::INTEGER,
+ self::PROP_BACKUPS => ObjectType::INTEGER,
+ self::PROP_WRITE_SYNCHRONIZATION_MODE => ObjectType::INTEGER,
+ self::PROP_COPY_ON_READ => ObjectType::BOOLEAN,
+ self::PROP_READ_FROM_BACKUP => ObjectType::BOOLEAN,
+ self::PROP_DATA_REGION_NAME => ObjectType::STRING,
+ self::PROP_IS_ONHEAP_CACHE_ENABLED => ObjectType::BOOLEAN,
+ self::PROP_QUERY_ENTITY => new ObjectArrayType((new ComplexObjectType())->setPhpClassName(QueryEntity::class)),
+ self::PROP_QUERY_PARALLELISM => ObjectType::INTEGER,
+ self::PROP_QUERY_DETAIL_METRICS_SIZE => ObjectType::INTEGER,
+ self::PROP_SQL_SCHEMA => ObjectType::STRING,
+ self::PROP_SQL_INDEX_INLINE_MAX_SIZE => ObjectType::INTEGER,
+ self::PROP_SQL_ESCAPE_ALL => ObjectType::BOOLEAN,
+ self::PROP_MAX_QUERY_ITERATORS => ObjectType::INTEGER,
+ self::PROP_REBALANCE_MODE => ObjectType::INTEGER,
+ self::PROP_REBALANCE_DELAY => ObjectType::LONG,
+ self::PROP_REBALANCE_TIMEOUT => ObjectType::LONG,
+ self::PROP_REBALANCE_BATCH_SIZE => ObjectType::INTEGER,
+ self::PROP_REBALANCE_BATCHES_PREFETCH_COUNT => ObjectType::LONG,
+ self::PROP_REBALANCE_ORDER => ObjectType::INTEGER,
+ self::PROP_REBALANCE_THROTTLE => ObjectType::LONG,
+ self::PROP_GROUP_NAME => ObjectType::STRING,
+ self::PROP_CACHE_KEY_CONFIGURATION => new ObjectArrayType((new ComplexObjectType())->setPhpClassName(CacheKeyConfiguration::class)),
+ self::PROP_DEFAULT_LOCK_TIMEOUT => ObjectType::LONG,
+ self::PROP_MAX_CONCURRENT_ASYNC_OPS => ObjectType::INTEGER,
+ self::PROP_PARTITION_LOSS_POLICY => ObjectType::INTEGER,
+ self::PROP_EAGER_TTL => ObjectType::BOOLEAN,
+ self::PROP_STATISTICS_ENABLED => ObjectType::BOOLEAN
+ );
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function write(BinaryCommunicator $communicator, MessageBuffer $buffer, string $name): void
+ {
+ $this->setName($name);
+
+ $startPos = $buffer->getPosition();
+ $buffer->setPosition($startPos +
+ BinaryUtils::getSize(ObjectType::INTEGER) +
+ BinaryUtils::getSize(ObjectType::SHORT));
+
+ foreach ($this->properties as $propertyCode => $property) {
+ $this->writeProperty($communicator, $buffer, $propertyCode, $property);
+ }
+
+ $length = $buffer->getPosition() - $startPos;
+ $buffer->setPosition($startPos);
+
+ $buffer->writeInteger($length);
+ $buffer->writeShort(count($this->properties));
+ }
+
+ private function writeProperty(BinaryCommunicator $communicator, MessageBuffer $buffer, int $propertyCode, $property): void
+ {
+ $buffer->writeShort($propertyCode);
+ $propertyType = self::$propInfo[$propertyCode];
+ switch (BinaryUtils::getTypeCode($propertyType)) {
+ case ObjectType::INTEGER:
+ case ObjectType::LONG:
+ case ObjectType::BOOLEAN:
+ $communicator->writeObject($buffer, $property, $propertyType, false);
+ return;
+ case ObjectType::STRING:
+ $communicator->writeObject($buffer, $property, $propertyType);
+ return;
+ case ObjectType::OBJECT_ARRAY:
+ $length = $property ? count($property) : 0;
+ $buffer->writeInteger($length);
+ foreach ($property as $prop) {
+ $prop->write($communicator, $buffer);
+ }
+ return;
+ default:
+ BinaryUtils::internalError();
+ }
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function read(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ //length
+ $buffer->readInteger();
+ $this->readProperty($communicator, $buffer, self::PROP_ATOMICITY_MODE);
+ $this->readProperty($communicator, $buffer, self::PROP_BACKUPS);
+ $this->readProperty($communicator, $buffer, self::PROP_CACHE_MODE);
+ $this->readProperty($communicator, $buffer, self::PROP_COPY_ON_READ);
+ $this->readProperty($communicator, $buffer, self::PROP_DATA_REGION_NAME);
+ $this->readProperty($communicator, $buffer, self::PROP_EAGER_TTL);
+ $this->readProperty($communicator, $buffer, self::PROP_STATISTICS_ENABLED);
+ $this->readProperty($communicator, $buffer, self::PROP_GROUP_NAME);
+ $this->readProperty($communicator, $buffer, self::PROP_DEFAULT_LOCK_TIMEOUT);
+ $this->readProperty($communicator, $buffer, self::PROP_MAX_CONCURRENT_ASYNC_OPS);
+ $this->readProperty($communicator, $buffer, self::PROP_MAX_QUERY_ITERATORS);
+ $this->readProperty($communicator, $buffer, self::PROP_NAME);
+ $this->readProperty($communicator, $buffer, self::PROP_IS_ONHEAP_CACHE_ENABLED);
+ $this->readProperty($communicator, $buffer, self::PROP_PARTITION_LOSS_POLICY);
+ $this->readProperty($communicator, $buffer, self::PROP_QUERY_DETAIL_METRICS_SIZE);
+ $this->readProperty($communicator, $buffer, self::PROP_QUERY_PARALLELISM);
+ $this->readProperty($communicator, $buffer, self::PROP_READ_FROM_BACKUP);
+ $this->readProperty($communicator, $buffer, self::PROP_REBALANCE_BATCH_SIZE);
+ $this->readProperty($communicator, $buffer, self::PROP_REBALANCE_BATCHES_PREFETCH_COUNT);
+ $this->readProperty($communicator, $buffer, self::PROP_REBALANCE_DELAY);
+ $this->readProperty($communicator, $buffer, self::PROP_REBALANCE_MODE);
+ $this->readProperty($communicator, $buffer, self::PROP_REBALANCE_ORDER);
+ $this->readProperty($communicator, $buffer, self::PROP_REBALANCE_THROTTLE);
+ $this->readProperty($communicator, $buffer, self::PROP_REBALANCE_TIMEOUT);
+ $this->readProperty($communicator, $buffer, self::PROP_SQL_ESCAPE_ALL);
+ $this->readProperty($communicator, $buffer, self::PROP_SQL_INDEX_INLINE_MAX_SIZE);
+ $this->readProperty($communicator, $buffer, self::PROP_SQL_SCHEMA);
+ $this->readProperty($communicator, $buffer, self::PROP_WRITE_SYNCHRONIZATION_MODE);
+ $this->readProperty($communicator, $buffer, self::PROP_CACHE_KEY_CONFIGURATION);
+ $this->readProperty($communicator, $buffer, self::PROP_QUERY_ENTITY);
+ }
+
+ private function readProperty(BinaryCommunicator $communicator, MessageBuffer $buffer, int $propertyCode): void
+ {
+ $propertyType = self::$propInfo[$propertyCode];
+ switch (BinaryUtils::getTypeCode($propertyType)) {
+ case ObjectType::INTEGER:
+ case ObjectType::LONG:
+ case ObjectType::BOOLEAN:
+ $this->properties[$propertyCode] = $communicator->readTypedObject($buffer, $propertyType);
+ return;
+ case ObjectType::STRING:
+ $this->properties[$propertyCode] = $communicator->readObject($buffer, $propertyType);
+ return;
+ case ObjectType::OBJECT_ARRAY:
+ $length = $buffer->readInteger();
+ $properties = [];
+ for ($i = 0; $i < $length; $i++) {
+ $propClassName = $propertyType->getElementType()->getPhpClassName();
+ $property = new $propClassName();
+ $property->read($communicator, $buffer);
+ array_push($properties, $property);
+ }
+ $this->properties[$propertyCode] = $properties;
+ return;
+ default:
+ BinaryUtils::internalError();
+ }
+ }
+}
+
+CacheConfiguration::init();
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Cache/CacheEntry.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Cache/CacheEntry.php b/modules/platforms/php/src/Apache/Ignite/Cache/CacheEntry.php
new file mode 100644
index 0000000..bd933c6
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Cache/CacheEntry.php
@@ -0,0 +1,60 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Cache;
+
+/**
+ * A cache entry (key-value pair).
+ */
+class CacheEntry
+{
+ private $key;
+ private $value;
+
+ /**
+ * Public constructor.
+ *
+ * @param mixed $key key corresponding to this entry.
+ * @param mixed $value value associated with the key.
+ */
+ public function __construct($key, $value)
+ {
+ $this->key = $key;
+ $this->value = $value;
+ }
+
+ /**
+ * Returns the key corresponding to this entry.
+ *
+ * @return mixed the key corresponding to this entry.
+ */
+ public function getKey()
+ {
+ return $this->key;
+ }
+
+ /**
+ * Returns the value corresponding to this entry.
+ *
+ * @return mixed the value corresponding to this entry.
+ */
+ public function getValue()
+ {
+ return $this->value;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Cache/CacheInterface.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Cache/CacheInterface.php b/modules/platforms/php/src/Apache/Ignite/Cache/CacheInterface.php
new file mode 100644
index 0000000..a228073
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Cache/CacheInterface.php
@@ -0,0 +1,379 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Cache;
+
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Query\Query;
+use Apache\Ignite\Query\CursorInterface;
+
+/**
+ * Interface representing and providing access to Ignite cache.
+ *
+ * An instance of the class with this interface should be obtained via the methods of Ignite Client.
+ * One instance of such a class provides access to one Ignite cache which is specified
+ * during the instance obtaining and cannot be changed after that.
+ *
+ * There are three groups of methods in the cache interface:
+ * - methods to configure the interface itself (optionally specify Ignite type for cache key and/or value)
+ * - methods to operate with the cache using Key-Value Queries
+ * - methods to operate with the cache using SQL and Scan Queries
+ *
+ */
+interface CacheInterface
+{
+ /** @name PeekMode
+ * @anchor PeekMode
+ * @{
+ */
+
+ /**
+ * Peek mode ALL
+ */
+ const PEEK_MODE_ALL = 0;
+
+ /**
+ * Peek mode NEAR
+ */
+ const PEEK_MODE_NEAR = 1;
+
+ /**
+ * Peek mode PRIMARY
+ */
+ const PEEK_MODE_PRIMARY = 2;
+
+ /**
+ * Peek mode BACKUP
+ */
+ const PEEK_MODE_BACKUP = 3;
+ /** @} */ // end of PeekMode
+
+ /* Methods to configure the cache interface */
+
+ /**
+ * Specifies a type of the cache key.
+ *
+ * Ignite client assumes that keys in all further operations with the cache
+ * will have the Ignite type specified by this method.
+ * Eg. the client will convert keys provided as input parameters of the Key-Value or SQL operations
+ * to the specified Ignite object type before sending the keys to a server.
+ *
+ * By default a type of the cache key is not specified (null).
+ *
+ * If the type is not specified then during operations Ignite client
+ * will do automatic mapping between some of the PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * @param int|ObjectType|null $type type of the keys in the cache:
+ * - either a type code of primitive (simple) type
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (means the type is not specified).
+ *
+ * @return CacheInterface the same instance of the class.
+ *
+ * @throws ClientException if error.
+ */
+ public function setKeyType($type): CacheInterface;
+
+ /**
+ * Specifies a type of the cache value.
+ *
+ * Ignite client assumes that values in all further operations with the cache
+ * will have the Ignite type specified by this method.
+ * Eg. the client will convert values provided as input parameters of the Key-Value or SQL operations
+ * to the specified Ignite object type before sending the values to a server.
+ *
+ * By default a type of the cache value is not specified (null).
+ *
+ * If the type is not specified then during operations Ignite client
+ * will do automatic mapping between some of the PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * @param int|ObjectType|null $type type of the values in the cache:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (means the type is not specified).
+ *
+ * @return CacheInterface the same instance of the class.
+ *
+ * @throws ClientException if error.
+ */
+ public function setValueType($type): CacheInterface;
+
+ /* Methods to operate with the cache using Key-Value Queries */
+
+ /**
+ * Retrieves a value associated with the specified key from the cache.
+ *
+ * @param mixed $key key.
+ *
+ * @return mixed value associated with the specified key, or null if it does not exist.
+ *
+ * @throws ClientException if error.
+ */
+ public function get($key);
+
+ /**
+ * Retrieves entries associated with the specified keys from the cache.
+ *
+ * @param array $keys keys.
+ *
+ * @return array the retrieved entries (key-value pairs) of CacheEntry.
+ * Entries with the keys which do not exist in the cache are not included into the array.
+ *
+ * @throws ClientException if error.
+ */
+ public function getAll(array $keys): array;
+
+ /**
+ * Associates the specified value with the specified key in the cache.
+ *
+ * Overwrites the previous value if the key exists in the cache,
+ * otherwise creates new entry (key-value pair).
+ *
+ * @param mixed $key key
+ * @param mixed $value value to be associated with the specified key.
+ *
+ * @throws ClientException if error.
+ */
+ public function put($key, $value): void;
+
+ /**
+ * Associates the specified values with the specified keys in the cache.
+ *
+ * Overwrites the previous value if a key exists in the cache,
+ * otherwise creates new entry (key-value pair).
+ *
+ * @param array $entries entries (key-value pairs) of CacheEntry to be put into the cache.
+ *
+ * @throws ClientException if error.
+ */
+ public function putAll(array $entries): void;
+
+ /**
+ * Checks if the specified key exists in the cache.
+ *
+ * @param mixed $key key to check.
+ *
+ * @return bool true if the key exists, false otherwise.
+ *
+ * @throws ClientException if error.
+ */
+ public function containsKey($key): bool;
+
+ /**
+ * Checks if all the specified keys exist in the cache.
+ *
+ * @param array $keys keys to check.
+ *
+ * @return bool true if all the keys exist,
+ * false if at least one of the keys does not exist in the cache.
+ *
+ * @throws ClientException if error.
+ */
+ public function containsKeys(array $keys): bool;
+
+ /**
+ * Associates the specified value with the specified key in the cache
+ * and returns the previous associated value, if any.
+ *
+ * Overwrites the previous value if the key exists in the cache,
+ * otherwise creates new entry (key-value pair).
+ *
+ * @param mixed $key key.
+ * @param mixed $value value to be associated with the specified key.
+ *
+ * @return mixed the previous value associated with the specified key, or null if it did not exist.
+ *
+ * @throws ClientException if error.
+ */
+ public function getAndPut($key, $value);
+
+ /**
+ * Associates the specified value with the specified key in the cache
+ * and returns the previous associated value, if the key exists in the cache.
+ * Otherwise does nothing and returns null.
+ *
+ * @param mixed $key key.
+ * @param mixed $value value to be associated with the specified key.
+ *
+ * @return mixed the previous value associated with the specified key, or null if it did not exist.
+ *
+ * @throws ClientException if error.
+ */
+ public function getAndReplace($key, $value);
+
+ /**
+ * Removes the cache entry with the specified key and returns the last associated value, if any.
+ *
+ * @param mixed $key key of the entry to be removed.
+ *
+ * @return mixed the last value associated with the specified key, or null if it did not exist.
+ *
+ * @throws ClientException if error.
+ */
+ public function getAndRemove($key);
+
+ /**
+ * Creates new entry (key-value pair) if the specified key does not exist in the cache.
+ * Otherwise does nothing.
+ *
+ * @param mixed $key key.
+ * @param mixed $value value to be associated with the specified key.
+ *
+ * @return true if the operation has been done, false otherwise.
+ *
+ * @throws ClientException if error.
+ */
+ public function putIfAbsent($key, $value): bool;
+
+ /**
+ * Creates new entry (key-value pair) if the specified key does not exist in the cache.
+ * Otherwise returns the current value associated with the existing key.
+ *
+ * @param mixed $key key.
+ * @param mixed $value value to be associated with the specified key.
+ *
+ * @return mixed the current value associated with the key if it already exists in the cache,
+ * null if the new entry is created.
+ *
+ * @throws ClientException if error.
+ */
+ public function getAndPutIfAbsent($key, $value);
+
+ /**
+ * Associates the specified value with the specified key, if the key exists in the cache.
+ * Otherwise does nothing.
+ *
+ * @param mixed $key key.
+ * @param mixed $value value to be associated with the specified key.
+ *
+ * @return bool true if the operation has been done, false otherwise.
+ *
+ * @throws ClientException if error.
+ */
+ public function replace($key, $value): bool;
+
+ /**
+ * Associates the new value with the specified key, if the key exists in the cache
+ * and the current value equals to the provided one.
+ * Otherwise does nothing.
+ *
+ * @param mixed $key key.
+ * @param mixed $value value to be compared with the current value associated with the specified key.
+ * @param mixed $newValue new value to be associated with the specified key.
+ *
+ * @return bool true if the operation has been done, false otherwise.
+ *
+ * @throws ClientException if error.
+ */
+ public function replaceIfEquals($key, $value, $newValue): bool;
+
+ /**
+ * Removes all entries from the cache, without notifying listeners and cache writers.
+ *
+ * @throws ClientException if error.
+ */
+ public function clear(): void;
+
+ /**
+ * Removes entry with the specified key from the cache, without notifying listeners and cache writers.
+ *
+ * @param mixed $key key to be removed.
+ *
+ * @throws ClientException if error.
+ */
+ public function clearKey($key): void;
+
+ /**
+ * Removes entries with the specified keys from the cache, without notifying listeners and cache writers.
+ *
+ * @param array $keys keys to be removed.
+ *
+ * @throws ClientException if error.
+ */
+ public function clearKeys($keys): void;
+
+ /**
+ * Removes entry with the specified key from the cache, notifying listeners and cache writers.
+ *
+ * @param mixed $key key to be removed.
+ *
+ * @return bool true if the operation has been done, false otherwise.
+ *
+ * @throws ClientException if error.
+ */
+ public function removeKey($key): bool;
+
+ /**
+ * Removes entry with the specified key from the cache, if the current value equals to the provided one.
+ * Notifies listeners and cache writers.
+ *
+ * @param mixed $key key to be removed.
+ * @param mixed $value value to be compared with the current value associated with the specified key.
+ *
+ * @return bool true if the operation has been done, false otherwise.
+ *
+ * @throws ClientException if error.
+ */
+ public function removeIfEquals($key, $value): bool;
+
+ /**
+ * Removes entries with the specified keys from the cache, notifying listeners and cache writers.
+ *
+ * @param array $keys keys to be removed.
+ *
+ * @throws ClientException if error.
+ */
+ public function removeKeys($keys): void;
+
+ /**
+ * Removes all entries from the cache, notifying listeners and cache writers.
+ *
+ * @throws ClientException if error.
+ */
+ public function removeAll(): void;
+
+ /**
+ * Returns the number of the entries in the cache.
+ *
+ * @param int ...$peekModes peek modes, values from @ref PeekMode constants.
+ *
+ * @return int the number of the entries in the cache.
+ *
+ * @throws ClientException if error.
+ */
+ public function getSize(int ...$peekModes): int;
+
+ /* Methods to operate with the cache using SQL and Scan Queries */
+
+ /**
+ * Starts an SQL, SQL Fields or Scan query operation.
+ *
+ * @param Query $query query to be executed.
+ *
+ * @return CursorInterface new instance of the class with interface representing a cursor
+ * to obtain the results of the query operation:
+ * - SqlFieldsCursorInterface in case of SqlFieldsQuery query
+ * - CursorInterface in case of other types of query
+ *
+ * @throws ClientException if error.
+ */
+ public function query(Query $query): CursorInterface;
+}
[8/9] ignite git commit: IGNITE-7783: PHP thin client
Posted by is...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/api_docs/Doxyfile
----------------------------------------------------------------------
diff --git a/modules/platforms/php/api_docs/Doxyfile b/modules/platforms/php/api_docs/Doxyfile
new file mode 100644
index 0000000..f0a37a3
--- /dev/null
+++ b/modules/platforms/php/api_docs/Doxyfile
@@ -0,0 +1,2472 @@
+# Doxyfile 1.8.14
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "PHP Client for Apache Ignite"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = api_docs
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines (in the resulting output). You can put ^^ in the value part of an
+# alias to insert a newline as if a physical newline was in the original file.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS = *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE = src/Apache/Ignite/Internal
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files
+# were built. This is equivalent to specifying the "-p" option to a clang tool,
+# such as clang-check. These options will then be passed to the parser.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: 0.
+
+CLANG_COMPILATION_DATABASE_PATH = 0
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via Javascript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have Javascript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: https://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options f
<TRUNCATED>
[4/9] ignite git commit: IGNITE-7783: PHP thin client
Posted by is...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Binary/TypeInfo.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Binary/TypeInfo.php b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/TypeInfo.php
new file mode 100644
index 0000000..9ab4057
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/TypeInfo.php
@@ -0,0 +1,312 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Binary;
+
+use Apache\Ignite\Type\ObjectType;
+
+class TypeInfo
+{
+ const NAME = 'name';
+ const SIZE = 'size';
+ const MIN_VALUE = 'min';
+ const MAX_VALUE = 'max';
+ const MAX_UNSIGNED_VALUE = 'max_unsigned';
+ const NULLABLE = 'nullable';
+ const ELEMENT_TYPE_CODE = 'element_type';
+ const KEEP_ELEMENT_TYPE = 'keep_element_type';
+ const MAX_INT_VALUE = 2147483647;
+
+ private $properties;
+
+ private static $info;
+ private static $primitiveTypes;
+
+ public static function init(): void
+ {
+ TypeInfo::$info = array(
+ ObjectType::BYTE => new TypeInfo([
+ TypeInfo::NAME => 'byte',
+ TypeInfo::SIZE => 1,
+ TypeInfo::MIN_VALUE => -128,
+ TypeInfo::MAX_VALUE => 127,
+ TypeInfo::MAX_UNSIGNED_VALUE => 0x100,
+ ]),
+ ObjectType::SHORT => new TypeInfo([
+ TypeInfo::NAME => 'short',
+ TypeInfo::SIZE => 2,
+ TypeInfo::MIN_VALUE => -32768,
+ TypeInfo::MAX_VALUE => 32767,
+ TypeInfo::MAX_UNSIGNED_VALUE => 0x10000,
+ ]),
+ ObjectType::INTEGER => new TypeInfo([
+ TypeInfo::NAME => 'integer',
+ TypeInfo::SIZE => 4,
+ TypeInfo::MIN_VALUE => -2147483648,
+ TypeInfo::MAX_VALUE => TypeInfo::MAX_INT_VALUE,
+ ]),
+ ObjectType::LONG => new TypeInfo([
+ TypeInfo::NAME => 'long',
+ TypeInfo::SIZE => 8,
+ ]),
+ ObjectType::FLOAT => new TypeInfo([
+ TypeInfo::NAME => 'float',
+ TypeInfo::SIZE => 4,
+ ]),
+ ObjectType::DOUBLE => new TypeInfo([
+ TypeInfo::NAME => 'double',
+ TypeInfo::SIZE => 8,
+ ]),
+ ObjectType::CHAR => new TypeInfo([
+ TypeInfo::NAME => 'char',
+ TypeInfo::SIZE => 2,
+ ]),
+ ObjectType::BOOLEAN => new TypeInfo([
+ TypeInfo::NAME => 'boolean',
+ TypeInfo::SIZE => 1,
+ ]),
+ ObjectType::STRING => new TypeInfo([
+ TypeInfo::NAME => 'string',
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::UUID => new TypeInfo([
+ TypeInfo::NAME => 'UUID',
+ TypeInfo::SIZE => 16,
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::DATE => new TypeInfo([
+ TypeInfo::NAME => 'date',
+ TypeInfo::SIZE => 8,
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::BYTE_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'byte array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::BYTE
+ ]),
+ ObjectType::SHORT_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'short array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::SHORT
+ ]),
+ ObjectType::INTEGER_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'integer array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::INTEGER
+ ]),
+ ObjectType::LONG_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'long array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::LONG
+ ]),
+ ObjectType::FLOAT_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'float array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::FLOAT
+ ]),
+ ObjectType::DOUBLE_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'double array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::DOUBLE
+ ]),
+ ObjectType::CHAR_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'char array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::CHAR
+ ]),
+ ObjectType::BOOLEAN_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'boolean array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::BOOLEAN
+ ]),
+ ObjectType::STRING_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'string array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::STRING,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::UUID_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'UUID array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::UUID,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::DATE_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'date array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::DATE,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::OBJECT_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'object array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::COMPLEX_OBJECT,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::COLLECTION => new TypeInfo([
+ TypeInfo::NAME => 'collection',
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::MAP => new TypeInfo([
+ TypeInfo::NAME => 'map',
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::ENUM => new TypeInfo([
+ TypeInfo::NAME => 'enum',
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::ENUM_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'enum array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::ENUM,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::DECIMAL => new TypeInfo([
+ TypeInfo::NAME => 'decimal',
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::DECIMAL_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'decimal array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::DECIMAL,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::TIMESTAMP => new TypeInfo([
+ TypeInfo::NAME => 'timestamp',
+ TypeInfo::SIZE => 12,
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::TIMESTAMP_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'timestamp array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::TIMESTAMP,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::TIME => new TypeInfo([
+ TypeInfo::NAME => 'time',
+ TypeInfo::SIZE => 8,
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::TIME_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'time array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::TIME,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::NULL => new TypeInfo([
+ TypeInfo::NAME => 'null',
+ TypeInfo::NULLABLE => true,
+ ])
+ );
+
+ TypeInfo::$primitiveTypes = [
+ ObjectType::BYTE,
+ ObjectType::SHORT,
+ ObjectType::INTEGER,
+ ObjectType::LONG,
+ ObjectType::FLOAT,
+ ObjectType::DOUBLE,
+ ObjectType::CHAR,
+ ObjectType::BOOLEAN,
+ ObjectType::STRING,
+ ObjectType::UUID,
+ ObjectType::DATE,
+ ObjectType::BYTE_ARRAY,
+ ObjectType::SHORT_ARRAY,
+ ObjectType::INTEGER_ARRAY,
+ ObjectType::LONG_ARRAY,
+ ObjectType::FLOAT_ARRAY,
+ ObjectType::DOUBLE_ARRAY,
+ ObjectType::CHAR_ARRAY,
+ ObjectType::BOOLEAN_ARRAY,
+ ObjectType::STRING_ARRAY,
+ ObjectType::UUID_ARRAY,
+ ObjectType::DATE_ARRAY,
+ ObjectType::ENUM,
+ ObjectType::ENUM_ARRAY,
+ ObjectType::DECIMAL,
+ ObjectType::DECIMAL_ARRAY,
+ ObjectType::TIMESTAMP,
+ ObjectType::TIMESTAMP_ARRAY,
+ ObjectType::TIME,
+ ObjectType::TIME_ARRAY
+ ];
+ }
+
+ public static function getTypeInfo(int $typeCode): ?TypeInfo
+ {
+ return array_key_exists($typeCode, TypeInfo::$info) ? TypeInfo::$info[$typeCode] : null;
+ }
+
+ public static function getPrimitiveTypes(): array
+ {
+ return TypeInfo::$primitiveTypes;
+ }
+
+ private function __construct(array $properties)
+ {
+ $this->properties = $properties;
+ }
+
+ public function getName(): string
+ {
+ return $this->getProperty(TypeInfo::NAME, null);
+ }
+
+ public function getSize(): int
+ {
+ return $this->getProperty(TypeInfo::SIZE, 0);
+ }
+
+ public function isNullable(): bool
+ {
+ return $this->getProperty(TypeInfo::NULLABLE, false);
+ }
+
+ public function getElementTypeCode(): int
+ {
+ return $this->getProperty(TypeInfo::ELEMENT_TYPE_CODE, 0);
+ }
+
+ public function keepElementType(): bool
+ {
+ return $this->getProperty(TypeInfo::KEEP_ELEMENT_TYPE, false);
+ }
+
+ public function getMinValue()
+ {
+ return $this->getProperty(TypeInfo::MIN_VALUE, null);
+ }
+
+ public function getMaxValue()
+ {
+ return $this->getProperty(TypeInfo::MAX_VALUE, null);
+ }
+
+ public function getMaxUnsignedValue()
+ {
+ return $this->getProperty(TypeInfo::MAX_UNSIGNED_VALUE, null);
+ }
+
+ private function getProperty(string $propName, $defaultValue)
+ {
+ return array_key_exists($propName, $this->properties) ? $this->properties[$propName] : $defaultValue;
+ }
+}
+
+TypeInfo::init();
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Cache.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Cache.php b/modules/platforms/php/src/Apache/Ignite/Internal/Cache.php
new file mode 100644
index 0000000..fe0965e
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Cache.php
@@ -0,0 +1,387 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal;
+
+use Apache\Ignite\Cache\CacheInterface;
+use Apache\Ignite\Cache\CacheEntry;
+use Apache\Ignite\Query\Query;
+use Apache\Ignite\Query\CursorInterface;
+use Apache\Ignite\Internal\Binary\ClientOperation;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+
+class Cache implements CacheInterface
+{
+ private $name;
+ private $id;
+ private $keyType;
+ private $valueType;
+ private $communicator;
+
+ public function __construct(string $name, BinaryCommunicator $communicator)
+ {
+ $this->name = $name;
+ $this->id = Cache::calculateId($this->name);
+ $this->communicator = $communicator;
+ $this->keyType = null;
+ $this->valueType = null;
+ }
+
+ public static function calculateId(string $name)
+ {
+ return BinaryUtils::hashCode($name);
+ }
+
+ public function setKeyType($type): CacheInterface
+ {
+ BinaryUtils::checkObjectType($type, 'type');
+ $this->keyType = $type;
+ return $this;
+ }
+
+ public function setValueType($type): CacheInterface
+ {
+ BinaryUtils::checkObjectType($type, 'type');
+ $this->valueType = $type;
+ return $this;
+ }
+
+ public function get($key)
+ {
+ return $this->writeKeyReadValueOp(ClientOperation::CACHE_GET, $key);
+ }
+
+ public function getAll(array $keys): array
+ {
+ ArgumentChecker::notEmpty($keys, 'keys');
+ $result = [];
+ $this->communicator->send(
+ ClientOperation::CACHE_GET_ALL,
+ function (MessageBuffer $payload) use ($keys)
+ {
+ $this->writeCacheInfo($payload);
+ $this->writeKeys($payload, $keys);
+ },
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $resultCount = $payload->readInteger();
+ for ($i = 0; $i < $resultCount; $i++) {
+ array_push($result, new CacheEntry(
+ $this->communicator->readObject($payload, $this->keyType),
+ $this->communicator->readObject($payload, $this->valueType)));
+ }
+ });
+ return $result;
+ }
+
+ public function put($key, $value): void
+ {
+ $this->writeKeyValueOp(ClientOperation::CACHE_PUT, $key, $value);
+ }
+
+ public function putAll(array $entries): void
+ {
+ ArgumentChecker::notEmpty($entries, 'entries');
+ ArgumentChecker::hasType($entries, 'entries', true, CacheEntry::class);
+ $this->communicator->send(
+ ClientOperation::CACHE_PUT_ALL,
+ function (MessageBuffer $payload) use ($entries)
+ {
+ $this->writeCacheInfo($payload);
+ $payload->writeInteger(count($entries));
+ foreach ($entries as $entry) {
+ $this->writeKeyValue($payload, $entry->getKey(), $entry->getValue());
+ }
+ });
+ }
+
+ public function containsKey($key): bool
+ {
+ return $this->writeKeyReadBooleanOp(ClientOperation::CACHE_CONTAINS_KEY, $key);
+ }
+
+ public function containsKeys(array $keys): bool
+ {
+ return $this->writeKeysReadBooleanOp(ClientOperation::CACHE_CONTAINS_KEYS, $keys);
+ }
+
+ public function getAndPut($key, $value)
+ {
+ return $this->writeKeyValueReadValueOp(ClientOperation::CACHE_GET_AND_PUT, $key, $value);
+ }
+
+ public function getAndReplace($key, $value)
+ {
+ return $this->writeKeyValueReadValueOp(ClientOperation::CACHE_GET_AND_REPLACE, $key, $value);
+ }
+
+ public function getAndRemove($key)
+ {
+ return $this->writeKeyReadValueOp(ClientOperation::CACHE_GET_AND_REMOVE, $key);
+ }
+
+ public function putIfAbsent($key, $value): bool
+ {
+ return $this->writeKeyValueReadBooleanOp(ClientOperation::CACHE_PUT_IF_ABSENT, $key, $value);
+ }
+
+ public function getAndPutIfAbsent($key, $value)
+ {
+ return $this->writeKeyValueReadValueOp(ClientOperation::CACHE_GET_AND_PUT_IF_ABSENT, $key, $value);
+ }
+
+ public function replace($key, $value): bool
+ {
+ return $this->writeKeyValueReadBooleanOp(ClientOperation::CACHE_REPLACE, $key, $value);
+ }
+
+ public function replaceIfEquals($key, $value, $newValue): bool
+ {
+ ArgumentChecker::notNull($key, 'key');
+ ArgumentChecker::notNull($value, 'value');
+ ArgumentChecker::notNull($newValue, 'newValue');
+ $result = false;
+ $this->communicator->send(
+ ClientOperation::CACHE_REPLACE_IF_EQUALS,
+ function (MessageBuffer $payload) use ($key, $value, $newValue)
+ {
+ $this->writeCacheInfo($payload);
+ $this->writeKeyValue($payload, $key, $value);
+ $this->communicator->writeObject($payload, $newValue, $this->valueType);
+ },
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $result = $payload->readBoolean();
+ });
+ return $result;
+ }
+
+ public function clear(): void
+ {
+ $this->communicator->send(
+ ClientOperation::CACHE_CLEAR,
+ function (MessageBuffer $payload)
+ {
+ $this->writeCacheInfo($payload);
+ });
+ }
+
+ public function clearKey($key): void
+ {
+ $this->writeKeyOp(ClientOperation::CACHE_CLEAR_KEY, $key);
+ }
+
+ public function clearKeys($keys): void
+ {
+ $this->writeKeysOp(ClientOperation::CACHE_CLEAR_KEYS, $keys);
+ }
+
+ public function removeKey($key): bool
+ {
+ return $this->writeKeyReadBooleanOp(ClientOperation::CACHE_REMOVE_KEY, $key);
+ }
+
+ public function removeIfEquals($key, $value): bool
+ {
+ return $this->writeKeyValueReadBooleanOp(ClientOperation::CACHE_REMOVE_IF_EQUALS, $key, $value);
+ }
+
+ public function removeKeys($keys): void
+ {
+ $this->writeKeysOp(ClientOperation::CACHE_REMOVE_KEYS, $keys);
+ }
+
+ public function removeAll(): void
+ {
+ $this->communicator->send(
+ ClientOperation::CACHE_REMOVE_ALL,
+ function (MessageBuffer $payload)
+ {
+ $this->writeCacheInfo($payload);
+ });
+ }
+
+ public function getSize(int ...$peekModes): int
+ {
+ ArgumentChecker::hasValueFrom($peekModes, 'peekModes', true, [
+ CacheInterface::PEEK_MODE_ALL,
+ CacheInterface::PEEK_MODE_NEAR,
+ CacheInterface::PEEK_MODE_PRIMARY,
+ CacheInterface::PEEK_MODE_BACKUP
+ ]);
+ $result = 0;
+ $this->communicator->send(
+ ClientOperation::CACHE_GET_SIZE,
+ function (MessageBuffer $payload) use ($peekModes)
+ {
+ $this->writeCacheInfo($payload);
+ $payload->writeInteger(count($peekModes));
+ foreach ($peekModes as $mode) {
+ $payload->writeByte($mode);
+ }
+ },
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $result = $payload->readLong();
+ });
+ return $result;
+ }
+
+ public function query(Query $query): CursorInterface
+ {
+ $value = null;
+ $this->communicator->send(
+ $query->getOperation(),
+ function (MessageBuffer $payload) use ($query)
+ {
+ $this->writeCacheInfo($payload);
+ $query->write($this->communicator, $payload);
+ },
+ function (MessageBuffer $payload) use ($query, &$value)
+ {
+ $value = $query->getCursor($this->communicator, $payload, $this->keyType, $this->valueType);
+ });
+ return $value;
+ }
+
+ private function writeCacheInfo(MessageBuffer $payload): void
+ {
+ $payload->writeInteger($this->id);
+ $payload->writeByte(0);
+ }
+
+ private function writeKeyValueOp(int $operation, $key, $value, callable $payloadReader = null): void
+ {
+ ArgumentChecker::notNull($key, 'key');
+ ArgumentChecker::notNull($value, 'value');
+ $this->communicator->send(
+ $operation,
+ function (MessageBuffer $payload) use ($key, $value)
+ {
+ $this->writeCacheInfo($payload);
+ $this->writeKeyValue($payload, $key, $value);
+ },
+ $payloadReader);
+ }
+
+ private function writeKeyValueReadValueOp(int $operation, $key, $value)
+ {
+ $result = null;
+ $this->writeKeyValueOp(
+ $operation, $key, $value,
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $result = $this->communicator->readObject($payload, $this->valueType);
+ });
+ return $result;
+ }
+
+ private function writeKeyValueReadBooleanOp(int $operation, $key, $value): bool
+ {
+ $result = false;
+ $this->writeKeyValueOp(
+ $operation, $key, $value,
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $result = $payload->readBoolean();
+ });
+ return $result;
+ }
+
+ private function writeKeyReadValueOp(int $operation, $key)
+ {
+ $value = null;
+ $this->writeKeyOp(
+ $operation, $key,
+ function (MessageBuffer $payload) use (&$value)
+ {
+ $value = $this->communicator->readObject($payload, $this->valueType);
+ });
+ return $value;
+ }
+
+ private function writeKeyOp(int $operation, $key, callable $payloadReader = null): void
+ {
+ ArgumentChecker::notNull($key, 'key');
+ $this->communicator->send(
+ $operation,
+ function (MessageBuffer $payload) use ($key)
+ {
+ $this->writeCacheInfo($payload);
+ $this->communicator->writeObject($payload, $key, $this->keyType);
+ },
+ $payloadReader);
+ }
+
+ private function writeKeyReadBooleanOp(int $operation, $key): bool
+ {
+ $result = false;
+ $this->writeKeyOp(
+ $operation,
+ $key,
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $result = $payload->readBoolean();
+ });
+ return $result;
+
+ }
+
+ private function writeKeys(MessageBuffer $payload, array $keys): void
+ {
+ $payload->writeInteger(count($keys));
+ foreach ($keys as $key) {
+ $this->communicator->writeObject($payload, $key, $this->keyType);
+ }
+ }
+
+ private function writeKeysReadBooleanOp(int $operation, array $keys): bool
+ {
+ $result = false;
+ $this->writeKeysOp(
+ $operation,
+ $keys,
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $result = $payload->readBoolean();
+ });
+ return $result;
+ }
+
+ private function writeKeysOp(int $operation, array $keys, callable $payloadReader = null): void
+ {
+ ArgumentChecker::notEmpty($keys, 'keys');
+ $this->communicator->send(
+ $operation,
+ function (MessageBuffer $payload) use ($keys)
+ {
+ $this->writeCacheInfo($payload);
+ $this->writeKeys($payload, $keys);
+ },
+ $payloadReader);
+ }
+
+ private function writeKeyValue(MessageBuffer $payload, $key, $value): void
+ {
+ $this->communicator->writeObject($payload, $key, $this->keyType);
+ $this->communicator->writeObject($payload, $value, $this->valueType);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientFailoverSocket.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientFailoverSocket.php b/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientFailoverSocket.php
new file mode 100644
index 0000000..2600698
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientFailoverSocket.php
@@ -0,0 +1,134 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Connection;
+
+use Apache\Ignite\ClientConfiguration;
+use Apache\Ignite\Exception\NoConnectionException;
+use Apache\Ignite\Exception\OperationStatusUnknownException;
+use Apache\Ignite\Internal\Utils\Logger;
+
+class ClientFailoverSocket
+{
+ const STATE_DISCONNECTED = 0;
+ const STATE_CONNECTING = 1;
+ const STATE_CONNECTED = 2;
+
+ private $socket;
+ private $state;
+ private $config;
+ private $endpointsNumber;
+ private $endpointIndex;
+ private $reconnectRequired;
+
+ public function __construct()
+ {
+ $this->socket = null;
+ $this->state = ClientFailoverSocket::STATE_DISCONNECTED;
+ $this->reconnectRequired = false;
+ }
+
+ public function connect(ClientConfiguration $config): void
+ {
+ if ($this->state !== ClientFailoverSocket::STATE_DISCONNECTED) {
+ $this->disconnect();
+ }
+ $this->config = $config;
+ $this->endpointsNumber = count($this->config->getEndpoints());
+ $this->endpointIndex = rand(0, $this->endpointsNumber - 1);
+ $this->failoverConnect();
+ }
+
+ public function send(int $opCode, ?callable $payloadWriter, callable $payloadReader = null): void
+ {
+ if ($this->reconnectRequired) {
+ $this->failoverConnect();
+ $this->reconnectRequired = false;
+ }
+ if ($this->state !== ClientFailoverSocket::STATE_CONNECTED) {
+ throw new NoConnectionException();
+ }
+ try {
+ $this->socket->sendRequest($opCode, $payloadWriter, $payloadReader);
+ } catch (OperationStatusUnknownException $e) {
+ $this->disconnect();
+ $this->endpointIndex++;
+ $this->reconnectRequired = true;
+ throw $e;
+ }
+ }
+
+ public function disconnect(): void
+ {
+ if ($this->state !== ClientFailoverSocket::STATE_DISCONNECTED) {
+ $this->changeState(ClientFailoverSocket::STATE_DISCONNECTED);
+ if ($this->socket) {
+ $this->socket->disconnect();
+ $this->socket = null;
+ }
+ }
+ }
+
+ private function failoverConnect(): void
+ {
+ $errors = [];
+ for ($i = 0; $i < $this->endpointsNumber; $i++) {
+ $index = ($this->endpointIndex + $i) % $this->endpointsNumber;
+ $endpoint = $this->config->getEndpoints()[$index];
+ try {
+ $this->changeState(ClientFailoverSocket::STATE_CONNECTING, $endpoint);
+ $this->socket = new ClientSocket($endpoint, $this->config);
+ $this->socket->connect();
+ $this->changeState(ClientFailoverSocket::STATE_CONNECTED, $endpoint);
+ $this->endpointIndex = $index;
+ return;
+ } catch (NoConnectionException $e) {
+ Logger::logError($e->getMessage());
+ array_push($errors, sprintf('[%s] %s', $endpoint, $e->getMessage()));
+ $this->changeState(ClientFailoverSocket::STATE_DISCONNECTED, $endpoint);
+ }
+ }
+ $this->socket = null;
+ throw new NoConnectionException(implode(';', $errors));
+ }
+
+ private function changeState(int $state, ?string $endpoint = null): void
+ {
+ if (Logger::isDebug()) {
+ Logger::logDebug(sprintf('Socket %s: %s -> %s',
+ $endpoint ? $endpoint : ($this->socket ? $this->socket->getEndpoint() : ''),
+ $this->getState($this->state),
+ $this->getState($state)));
+ }
+ $this->state = $state;
+ }
+
+ private function getState(int $state)
+ {
+ switch ($state) {
+ case ClientFailoverSocket::STATE_DISCONNECTED:
+ return 'DISCONNECTED';
+ case ClientFailoverSocket::STATE_CONNECTING:
+ return 'CONNECTING';
+ case ClientFailoverSocket::STATE_CONNECTED:
+ return 'CONNECTED';
+ default:
+ return 'UNKNOWN';
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientSocket.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientSocket.php b/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientSocket.php
new file mode 100644
index 0000000..a35bb15
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientSocket.php
@@ -0,0 +1,247 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Connection;
+
+use Apache\Ignite\ClientConfiguration;
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Internal\Utils\Logger;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\Request;
+use Apache\Ignite\Exception\NoConnectionException;
+use Apache\Ignite\Exception\OperationException;
+use Apache\Ignite\Exception\OperationStatusUnknownException;
+
+class ClientSocket
+{
+ const HANDSHAKE_SUCCESS_STATUS_CODE = 1;
+ const REQUEST_SUCCESS_STATUS_CODE = 0;
+ const PORT_DEFAULT = 10800;
+ const SOCKET_CHUNK_SIZE_DEFAULT = 8192;
+ const HANDSHAKE_CODE = 1;
+ const CLIENT_CODE = 2;
+
+ private static $currentVersion;
+ private static $supportedVersions;
+
+ private $endpoint;
+ private $config;
+ private $socket;
+ private $sendChunkSize;
+ private $receiveChunkSize;
+ private $protocolVersion;
+
+ public function __construct(string $endpoint, ClientConfiguration $config)
+ {
+ $this->endpoint = $endpoint;
+ $this->config = $config;
+ $this->socket = null;
+ $this->sendChunkSize = $config->getSendChunkSize() > 0 ?
+ $config->getSendChunkSize() :
+ self::SOCKET_CHUNK_SIZE_DEFAULT;
+ $this->receiveChunkSize = $config->getReceiveChunkSize() > 0 ?
+ $config->getReceiveChunkSize() :
+ self::SOCKET_CHUNK_SIZE_DEFAULT;
+ $this->protocolVersion = null;
+ }
+
+ public function __destruct()
+ {
+ $this->disconnect();
+ }
+
+ public static function init(): void
+ {
+ ClientSocket::$currentVersion = ProtocolVersion::$V_1_2_0;
+ ClientSocket::$supportedVersions = [
+ ProtocolVersion::$V_1_2_0
+ ];
+ }
+
+ public function getEndpoint(): string
+ {
+ return $this->endpoint;
+ }
+
+ public function connect(): void
+ {
+ $tlsOptions = $this->config->getTLSOptions();
+ $options = ['socket' => ['tcp_nodelay' => $this->config->getTcpNoDelay()]];
+ if ($tlsOptions) {
+ $options['ssl'] = $tlsOptions;
+ }
+ $context = stream_context_create($options);
+ $errno = 0;
+ $errstr = null;
+ if (!($this->socket = stream_socket_client(
+ ($tlsOptions ? 'ssl://' : 'tcp://') . $this->endpoint,
+ $errno,
+ $errstr,
+ ini_get('default_socket_timeout'),
+ STREAM_CLIENT_CONNECT,
+ $context))) {
+ throw new NoConnectionException($errstr);
+ }
+ if ($this->config->getTimeout() > 0) {
+ $timeout = $this->config->getTimeout();
+ stream_set_timeout($this->socket, intdiv($timeout, 1000), $timeout % 1000);
+ }
+ // send handshake
+ $this->processRequest($this->getHandshakeRequest(ClientSocket::$currentVersion));
+ }
+
+ public function disconnect(): void
+ {
+ if ($this->socket !== false && $this->socket !== null) {
+ fclose($this->socket);
+ $this->socket = null;
+ }
+ }
+
+ private function getHandshakeRequest($version): Request
+ {
+ $this->protocolVersion = $version;
+ return new Request(-1, array($this, 'handshakePayloadWriter'), null, true);
+ }
+
+ public function handshakePayloadWriter(MessageBuffer $buffer): void
+ {
+ // Handshake code
+ $buffer->writeByte(ClientSocket::HANDSHAKE_CODE);
+ // Protocol version
+ $this->protocolVersion->write($buffer);
+ // Client code
+ $buffer->writeByte(ClientSocket::CLIENT_CODE);
+ if ($this->config->getUserName()) {
+ BinaryCommunicator::writeString($buffer, $this->config->getUserName());
+ BinaryCommunicator::writeString($buffer, $this->config->getPassword());
+ }
+ }
+
+ public function sendRequest(int $opCode, ?callable $payloadWriter, callable $payloadReader = null): void
+ {
+ $request = new Request($opCode, $payloadWriter, $payloadReader);
+ $this->processRequest($request);
+ }
+
+ private function processRequest(Request $request): void
+ {
+ $buffer = $request->getMessage();
+ $this->logMessage($request->getId(), true, $buffer);
+ $data = $buffer->getBuffer();
+ while (($length = strlen($data)) > 0) {
+ $written = fwrite($this->socket, $data, $this->sendChunkSize);
+ if ($length === $written) {
+ break;
+ }
+ if ($written === false || $written === 0) {
+ throw new OperationStatusUnknownException('Error while writing data to the server');
+ }
+ $data = substr($data, $written);
+ }
+ $this->processResponse($request);
+ }
+
+ private function receive(MessageBuffer $buffer, int $minSize): void
+ {
+ while ($buffer->getLength() < $minSize)
+ {
+ $chunk = fread($this->socket, $this->receiveChunkSize);
+ if ($chunk === false || $chunk === '') {
+ throw new OperationStatusUnknownException('Error while reading data from the server');
+ } else {
+ $buffer->append($chunk);
+ }
+ }
+ }
+
+ private function processResponse(Request $request): void
+ {
+ $buffer = new MessageBuffer(0);
+ $this->receive($buffer, BinaryUtils::getSize(ObjectType::INTEGER));
+ // Response length
+ $length = $buffer->readInteger();
+ $this->receive($buffer, $length + BinaryUtils::getSize(ObjectType::INTEGER));
+ if ($request->isHandshake()) {
+ $this->processHandshake($buffer);
+ } else {
+ // Request id
+ $requestId = $buffer->readLong();
+ if (!BinaryUtils::floatEquals($requestId, $request->getId())) {
+ BinaryUtils::internalError('Invalid response id: ' . $requestId);
+ }
+ // Status code
+ $isSuccess = ($buffer->readInteger() === ClientSocket::REQUEST_SUCCESS_STATUS_CODE);
+ if (!$isSuccess) {
+ // Error message
+ $errMessage = BinaryCommunicator::readString($buffer);
+ throw new OperationException($errMessage);
+ } else {
+ $payloadReader = $request->getPayloadReader();
+ if ($payloadReader) {
+ call_user_func($payloadReader, $buffer);
+ }
+ }
+ }
+ $this->logMessage($request->getId(), false, $buffer);
+ }
+
+ private function processHandshake(MessageBuffer $buffer): void
+ {
+ // Handshake status
+ if ($buffer->readByte() === ClientSocket::HANDSHAKE_SUCCESS_STATUS_CODE) {
+ return;
+ }
+ // Server protocol version
+ $serverVersion = new ProtocolVersion();
+ $serverVersion->read($buffer);
+ // Error message
+ $errMessage = BinaryCommunicator::readString($buffer);
+
+ if (!$this->isSupportedVersion($serverVersion)) {
+ throw new OperationException(
+ sprintf('Protocol version mismatch: client %s / server %s. Server details: %s',
+ $this->protocolVersion->toString(), $serverVersion->toString(), $errMessage));
+ } else {
+ $this->disconnect();
+ throw new OperationException($errMessage);
+ }
+ }
+
+ private function isSupportedVersion(ProtocolVersion $version): bool
+ {
+ foreach (ClientSocket::$supportedVersions as $supportedVersion) {
+ if ($supportedVersion->equals($version)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private function logMessage(int $requestId, bool $isRequest, MessageBuffer $buffer): void
+ {
+ if (Logger::isDebug()) {
+ Logger::logDebug(($isRequest ? 'Request: ' : 'Response: ') . $requestId);
+ Logger::logBuffer($buffer);
+ }
+ }
+}
+
+ClientSocket::init();
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ProtocolVersion.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ProtocolVersion.php b/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ProtocolVersion.php
new file mode 100644
index 0000000..3c3a64b
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ProtocolVersion.php
@@ -0,0 +1,82 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Connection;
+
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+
+class ProtocolVersion
+{
+ public static $V_1_2_0;
+
+ private $major;
+ private $minor;
+ private $patch;
+
+ public static function init(): void
+ {
+ ProtocolVersion::$V_1_2_0 = new ProtocolVersion(1, 2, 0);
+ }
+
+ public function __construct(int $major = 0, int $minor = 0, int $patch = 0)
+ {
+ $this->major = $major;
+ $this->minor = $minor;
+ $this->patch = $patch;
+ }
+
+ public function compareTo(ProtocolVersion $other): int
+ {
+ $diff = $this->major - $other->major;
+ if ($diff !== 0) {
+ return $diff;
+ }
+ $diff = $this->minor - $other->minor;
+ if ($diff !== 0) {
+ return $diff;
+ }
+ return $this->patch - $other->patch;
+ }
+
+ public function equals(ProtocolVersion $other): bool
+ {
+ return $this->compareTo($other) === 0;
+ }
+
+ public function toString(): string
+ {
+ return sprintf('%d.%d.%d', $this->major, $this->minor, $this->patch);
+ }
+
+ public function read(MessageBuffer $buffer): void
+ {
+ $this->major = $buffer->readShort();
+ $this->minor = $buffer->readShort();
+ $this->patch = $buffer->readShort();
+ }
+
+ public function write(MessageBuffer $buffer): void
+ {
+ $buffer->writeShort($this->major);
+ $buffer->writeShort($this->minor);
+ $buffer->writeShort($this->patch);
+ }
+}
+
+ProtocolVersion::init();
+
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Query/Cursor.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Query/Cursor.php b/modules/platforms/php/src/Apache/Ignite/Internal/Query/Cursor.php
new file mode 100644
index 0000000..a228dd4
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Query/Cursor.php
@@ -0,0 +1,166 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Query;
+
+use Apache\Ignite\Cache\CacheEntry;
+use Apache\Ignite\Query\CursorInterface;
+use Apache\Ignite\Internal\Binary\ClientOperation;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+
+class Cursor implements CursorInterface
+{
+ protected $communicator;
+ private $operation;
+ private $buffer;
+ private $keyType;
+ private $valueType;
+ protected $id;
+ private $hasNext;
+ private $values;
+ private $valueIndex;
+ private $rewinds;
+ private $index;
+
+ public function __construct(BinaryCommunicator $communicator, int $operation, MessageBuffer $buffer, $keyType = null, $valueType = null)
+ {
+ $this->communicator = $communicator;
+ $this->operation = $operation;
+ $this->buffer = $buffer;
+ $this->keyType = $keyType;
+ $this->valueType = $valueType;
+ $this->id = null;
+ $this->hasNext = false;
+ $this->values = null;
+ $this->valueIndex = 0;
+ $this->rewinds = 0;
+ $this->index = 0;
+ }
+
+ public function current()
+ {
+ return $this->values[$this->valueIndex];
+ }
+
+ public function key()
+ {
+ return $this->index;
+ }
+
+ public function next()
+ {
+ $this->valueIndex++;
+ $this->index++;
+ }
+
+ public function rewind(): void
+ {
+ $this->rewinds++;
+ }
+
+ public function valid(): bool
+ {
+ if ($this->rewinds > 1) {
+ return false;
+ }
+ if (!$this->values || $this->valueIndex >= count($this->values)) {
+ $this->obtainValues();
+ $this->valueIndex = 0;
+ }
+ return $this->values && $this->valueIndex < count($this->values);
+ }
+
+ public function getAll(): array
+ {
+ $result = [];
+ foreach ($this as $value) {
+ array_push($result, $value);
+ }
+ return $result;
+ }
+
+ public function close(): void
+ {
+ // Close cursor only if the server has more pages: the server closes cursor automatically on last page
+ if ($this->id && $this->hasNext) {
+ $this->communicator->send(
+ ClientOperation::RESOURCE_CLOSE,
+ function (MessageBuffer $payload)
+ {
+ $this->write($payload);
+ });
+ }
+ }
+
+ private function getNext(): void
+ {
+ $this->hasNext = false;
+ $this->values = null;
+ $this->buffer = null;
+ $this->communicator->send(
+ $this->operation,
+ function (MessageBuffer $payload)
+ {
+ $this->write($payload);
+ },
+ function (MessageBuffer $payload)
+ {
+ $this->buffer = $payload;
+ });
+ }
+
+ private function obtainValues(): void
+ {
+ if (!$this->buffer && $this->hasNext) {
+ $this->getNext();
+ }
+ $this->values = null;
+ if ($this->buffer) {
+ $this->read($this->buffer);
+ $this->buffer = null;
+ }
+ }
+
+ private function write(MessageBuffer $buffer): void
+ {
+ $buffer->writeLong($this->id);
+ }
+
+ public function readId(MessageBuffer $buffer): void
+ {
+ $this->id = $buffer->readLong();
+ }
+
+ protected function readRow(MessageBuffer $buffer)
+ {
+ return new CacheEntry(
+ $this->communicator->readObject($buffer, $this->keyType),
+ $this->communicator->readObject($buffer, $this->valueType));
+ }
+
+ private function read(MessageBuffer $buffer): void
+ {
+ $rowCount = $buffer->readInteger();
+ $this->values = [];
+ for ($i = 0; $i < $rowCount; $i++) {
+ array_push($this->values, $this->readRow($buffer));
+ }
+ $this->hasNext = $buffer->readBoolean();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Query/SqlFieldsCursor.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Query/SqlFieldsCursor.php b/modules/platforms/php/src/Apache/Ignite/Internal/Query/SqlFieldsCursor.php
new file mode 100644
index 0000000..e876baf
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Query/SqlFieldsCursor.php
@@ -0,0 +1,75 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Query;
+
+use Apache\Ignite\Query\SqlFieldsCursorInterface;
+use Apache\Ignite\Internal\Binary\ClientOperation;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+
+class SqlFieldsCursor extends Cursor implements SqlFieldsCursorInterface
+{
+ private $fieldCount;
+ private $fieldNames;
+ private $fieldTypes;
+
+ public function __construct(BinaryCommunicator $communicator, MessageBuffer $buffer)
+ {
+ parent::__construct($communicator, ClientOperation::QUERY_SQL_FIELDS_CURSOR_GET_PAGE, $buffer);
+ $this->fieldCount = 0;
+ $this->fieldNames = [];
+ $this->fieldTypes = null;
+ }
+
+ public function getFieldNames(): array
+ {
+ return $this->fieldNames;
+ }
+
+ public function setFieldTypes(...$fieldTypes): SqlFieldsCursorInterface
+ {
+ foreach ($fieldTypes as $fieldType) {
+ BinaryUtils::checkObjectType($fieldType, 'fieldTypes');
+ }
+ $this->fieldTypes = $fieldTypes;
+ return $this;
+ }
+
+ public function readFieldNames(MessageBuffer $buffer, bool $includeFieldNames): void
+ {
+ $this->id = $buffer->readLong();
+ $this->fieldCount = $buffer->readInteger();
+ if ($includeFieldNames) {
+ for ($i = 0; $i < $this->fieldCount; $i++) {
+ array_push($this->fieldNames, $this->communicator->readObject($buffer));
+ }
+ }
+ }
+
+ protected function readRow(MessageBuffer $buffer)
+ {
+ $values = [];
+ for ($i = 0; $i < $this->fieldCount; $i++) {
+ $fieldType = $this->fieldTypes && $i < count($this->fieldTypes) ? $this->fieldTypes[$i] : null;
+ array_push($values, $this->communicator->readObject($buffer, $fieldType));
+ }
+ return $values;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Utils/ArgumentChecker.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Utils/ArgumentChecker.php b/modules/platforms/php/src/Apache/Ignite/Internal/Utils/ArgumentChecker.php
new file mode 100644
index 0000000..bd04f10
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Utils/ArgumentChecker.php
@@ -0,0 +1,87 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Utils;
+
+use Apache\Ignite\Exception\ClientException;
+
+class ArgumentChecker
+{
+ public static function notEmpty($arg, string $argName): void
+ {
+ if (empty($arg)) {
+ ArgumentChecker::illegalArgument(sprintf('"%s" argument should not be empty', $argName));
+ }
+ }
+
+ public static function notNull($arg, string $argName): void
+ {
+ if (is_null($arg)) {
+ ArgumentChecker::illegalArgument(sprintf('"%s" argument should not be null', $argName));
+ }
+ }
+
+ public static function hasType($arg, string $argName, bool $isArray, ...$types): void
+ {
+ if ($arg === null) {
+ return;
+ }
+ if ($isArray && is_array($arg)) {
+ foreach ($arg as $a) {
+ ArgumentChecker::hasType($a, $argName, false, ...$types);
+ }
+ } else {
+ foreach ($types as $type) {
+ if ($arg instanceof $type) {
+ return;
+ }
+ }
+ ArgumentChecker::illegalArgument(sprintf('"%s" argument has incorrect type', $argName));
+ }
+ }
+
+ public static function hasValueFrom($arg, string $argName, bool $isArray, array $values): void
+ {
+ if ($isArray && is_array($arg)) {
+ foreach ($arg as $a) {
+ ArgumentChecker::hasValueFrom($a, $argName, false, $values);
+ }
+ } else {
+ if (!in_array($arg, $values)) {
+ ArgumentChecker::invalidValue($argName);
+ }
+ }
+ }
+
+ public static function invalidValue(string $argName): void
+ {
+ ArgumentChecker::illegalArgument(sprintf('"%s" argument has incorrect value', $argName));
+ }
+
+ public static function invalidArgument($arg, string $argName, string $typeName): void
+ {
+ if ($arg !== null) {
+ ArgumentChecker::illegalArgument(sprintf('"%s" argument is invalid for %s', $argName, $typeName));
+ }
+ }
+
+ public static function illegalArgument($message): void
+ {
+ throw new ClientException($message);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Utils/Logger.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Utils/Logger.php b/modules/platforms/php/src/Apache/Ignite/Internal/Utils/Logger.php
new file mode 100644
index 0000000..1faf9ca
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Utils/Logger.php
@@ -0,0 +1,62 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Utils;
+
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+
+/** Utility class for logging errors and debug messages. */
+class Logger
+{
+ private static $debug = false;
+
+ public static function isDebug(): bool
+ {
+ return Logger::$debug;
+ }
+
+ public static function setDebug(bool $debug): void
+ {
+ Logger::$debug = $debug;
+ }
+
+ public static function logDebug($data, ...$args): void
+ {
+ if (Logger::$debug) {
+ echo(sprintf($data, ...$args) . PHP_EOL);
+ }
+ }
+
+ public static function logError($data, ...$args): void
+ {
+ if (Logger::$debug) {
+ echo(sprintf("ERROR: $data", ...$args) . PHP_EOL);
+ }
+ }
+
+ public static function logBuffer(MessageBuffer $buffer, int $startPos = 0, int $length = -1): void
+ {
+ if (Logger::$debug) {
+ if ($length < 0) {
+ $length = $buffer->getLength();
+ }
+ $message = $buffer->getSlice($startPos, $length);
+ Logger::logDebug('[' . implode(',', array_map('ord', str_split($message))) . ']');
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Query/CursorInterface.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Query/CursorInterface.php b/modules/platforms/php/src/Apache/Ignite/Query/CursorInterface.php
new file mode 100644
index 0000000..1525e28
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Query/CursorInterface.php
@@ -0,0 +1,56 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Query;
+
+/**
+ * Interface representing a cursor to obtain results of SQL and Scan query operations.
+ *
+ * An instance of the class with this interface should be obtained via query() method
+ * of an object with CacheInterface.
+ * One instance of the class with CursorInterface returns results of one SQL or Scan query operation.
+ *
+ * CursorInterface extends the PHP Iterator interface.
+ * The PHP Iterator's methods may be used to obtain the results of the query (cache entries, i.e. key-value pairs)
+ * one by one.
+ * Also, the cursor can be placed into the "foreach" PHP loop to easily iterate over all the results.
+ *
+ * Additionally, CursorInterface includes getAll() method to get all the results at once
+ * and close() method to prematurely close the cursor.
+ *
+ */
+interface CursorInterface extends \Iterator
+{
+ /**
+ * Returns all elements (cache entries, i.e. key-value pairs) from the query results at once.
+ *
+ * May be used instead of the PHP Iterator's methods if the number of returned entries
+ * is relatively small and will not cause memory utilization issues.
+ *
+ * @return array all cache entries (key-value pairs) returned by SQL or Scan query.
+ */
+ public function getAll(): array;
+
+ /**
+ * Closes the cursor. Obtaining elements from the results is not possible after this.
+ *
+ * This method should be called if no more elements are needed.
+ * It is not necessary to call it if all elements have been already obtained.
+ */
+ public function close(): void;
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Query/Query.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Query/Query.php b/modules/platforms/php/src/Apache/Ignite/Query/Query.php
new file mode 100644
index 0000000..2cd3aec
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Query/Query.php
@@ -0,0 +1,70 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Query;
+
+/**
+ * Base class representing an Ignite SQL or Scan query.
+ *
+ * The class is abstract, only subclasses may be instantiated.
+ */
+abstract class Query
+{
+ const PAGE_SIZE_DEFAULT = 1024;
+
+ protected $local;
+ protected $operation;
+ protected $pageSize;
+
+ protected function __construct(int $operation)
+ {
+ $this->operation = $operation;
+ $this->local = false;
+ $this->pageSize = Query::PAGE_SIZE_DEFAULT;
+ }
+
+ /**
+ * Set local query flag.
+ *
+ * @param bool $local local query flag: true or false.
+ * @return Query the same instance of the Query.
+ */
+ public function setLocal(bool $local): Query
+ {
+ $this->local = $local;
+ return $this;
+ }
+
+ /**
+ * Set cursor page size.
+ *
+ * @param int $pageSize cursor page size.
+ * @return Query the same instance of the Query.
+ */
+ public function setPageSize(int $pageSize): Query
+ {
+ $this->pageSize = $pageSize;
+ return $this;
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function getOperation(): int
+ {
+ return $this->operation;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Query/ScanQuery.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Query/ScanQuery.php b/modules/platforms/php/src/Apache/Ignite/Query/ScanQuery.php
new file mode 100644
index 0000000..85391b6
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Query/ScanQuery.php
@@ -0,0 +1,88 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Query;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\ClientOperation;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Query\Cursor;
+
+/**
+ * Class representing a Scan query which returns the whole cache entries (key-value pairs).
+ *
+ * This version of the class does not support a possibility to specify a Filter object for the query.
+ * The query returns all entries from the entire cache or from the specified partition.
+ */
+class ScanQuery extends Query
+{
+ private $partitionNumber;
+
+ /**
+ * Public constructor.
+ *
+ * Scan query settings have the following defaults:
+ * <pre>
+ * Scan Query setting : Default value
+ * Local query flag : false
+ * Cursor page size : 1024
+ * Partition number : -1 (entire cache)
+ * Filter object : null (not supported)
+ * </pre>
+ * Every setting (except Filter object) may be changed using set methods.
+ */
+ public function __construct()
+ {
+ parent::__construct(ClientOperation::QUERY_SCAN);
+ $this->partitionNumber = -1;
+ }
+
+ /**
+ * Sets a partition number over which this query should iterate.
+ *
+ * If negative, the query will iterate over all partitions in the cache.
+ *
+ * @param int $partitionNumber partition number over which this query should iterate.
+ *
+ * @return ScanQuery the same instance of the ScanQuery.
+ */
+ public function setPartitionNumber(int $partitionNumber): ScanQuery
+ {
+ $this->partitionNumber = $partitionNumber;
+ return $this;
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function write(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ // filter
+ $communicator->writeObject($buffer, null);
+ $buffer->writeInteger($this->pageSize);
+ $buffer->writeInteger($this->partitionNumber);
+ $buffer->writeBoolean($this->local);
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function getCursor(BinaryCommunicator $communicator, MessageBuffer $payload, $keyType = null, $valueType = null): CursorInterface
+ {
+ $cursor = new Cursor($communicator, ClientOperation::QUERY_SCAN_CURSOR_GET_PAGE, $payload, $keyType, $valueType);
+ $cursor->readId($payload);
+ return $cursor;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsCursorInterface.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsCursorInterface.php b/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsCursorInterface.php
new file mode 100644
index 0000000..77086bb
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsCursorInterface.php
@@ -0,0 +1,82 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Query;
+
+use Apache\Ignite\Type\ObjectType;
+
+/**
+ * Interface representing a cursor to obtain results of SQL Fields query operation.
+ *
+ * An instance of the class with this interface should be obtained via query() method
+ * of an object with CacheInterface.
+ * One instance of the class with SqlFieldsCursorInterface returns results of one SQL Fields query operation.
+ *
+ * SqlFieldsCursorInterface extends CursorInterface which extends the PHP Iterator interface.
+ * The PHP Iterator's methods may be used to obtain the results of the query (arrays with values of the fields)
+ * one by one.
+ * Also, the cursor can be placed into the "foreach" PHP loop to easily iterate over all the results.
+ *
+ * Additionally, SqlFieldsCursorInterface includes
+ * getAll() method to get all the results at once,
+ * getFieldNames() method to return names of the fields,
+ * setFieldTypes() method to specify Ignite types of the fields,
+ * and close() method (defined in CursorInterface) to prematurely close the cursor.
+ *
+ */
+interface SqlFieldsCursorInterface extends CursorInterface
+{
+ /**
+ * Returns all elements (arrays with values of the fields) from the query results at once.
+ *
+ * May be used instead of the PHP Iterator's methods if the number of returned elements
+ * is relatively small and will not cause memory utilization issues.
+ *
+ * @return array all results returned by SQL Fields query.
+ * Every element of the array is an array with values of the fields requested by the query.
+ */
+ public function getAll(): array;
+
+ /**
+ * Returns names of the fields which were requested in the SQL Fields query.
+ *
+ * Empty array is returned if "include field names" flag was false in the query.
+ *
+ * @return array field names.
+ * The order of names corresponds to the order of field values returned in the results of the query.
+ */
+ public function getFieldNames(): array;
+
+ /**
+ * Specifies Ignite types of the fields returned by the SQL Fields query.
+ *
+ * By default, an Ignite type of every field is not specified that means during operations Ignite client
+ * tries to make automatic mapping between PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * @param int|ObjectType|null ...$fieldTypes Ignite types of the returned fields.
+ * The order of types must correspond the order of field values returned in the results of the query.
+ * A type of every field can be:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (or not specified) that means the type is not specified
+ *
+ * @return SqlFieldsCursorInterface the same instance of the class with SqlFieldsCursorInterface.
+ */
+ public function setFieldTypes(...$fieldTypes): SqlFieldsCursorInterface;
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsQuery.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsQuery.php b/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsQuery.php
new file mode 100644
index 0000000..6025c64
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsQuery.php
@@ -0,0 +1,206 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Query;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\ClientOperation;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Query\SqlFieldsCursor;
+
+/**
+ * Class representing an SQL Fields query.
+ */
+class SqlFieldsQuery extends SqlQuery
+{
+ /** @name SqlFieldsQueryStatementType
+ * @anchor SqlFieldsQueryStatementType
+ * @{
+ */
+ const STATEMENT_TYPE_ANY = 0;
+ const STATEMENT_TYPE_SELECT = 1;
+ const STATEMENT_TYPE_UPDATE = 2;
+ /** @} */ // end of SqlFieldsQueryStatementType
+
+ private $schema;
+ private $maxRows;
+ private $statementType;
+ private $enforceJoinOrder;
+ private $collocated;
+ private $lazy;
+ private $includeFieldNames;
+
+ /**
+ * Public constructor.
+ *
+ * Requires SQL query string to be specified.
+ * Other SQL Fields query settings have the following defaults:
+ * <pre>
+ * SQL Fields Query setting : Default value
+ * Local query flag : false
+ * Cursor page size : 1024
+ * Query arguments : not specified
+ * Distributed joins flag : false
+ * Replicated only flag : false
+ * Timeout : 0 (disabled)
+ * Schema for the query : not specified
+ * Max rows : -1
+ * Statement type : STATEMENT_TYPE_ANY
+ * Enforce join order flag : false
+ * Collocated flag : false
+ * Lazy query execution flag : false
+ * Include field names flag : false
+ * </pre>
+ * Every setting may be changed using set methods.
+ *
+ * @param string $sql SQL query string.
+ *
+ * @throws ClientException if error.
+ */
+ public function __construct(string $sql)
+ {
+ parent::__construct(null, $sql);
+ $this->operation = ClientOperation::QUERY_SQL_FIELDS;
+ $this->schema = null;
+ $this->maxRows = -1;
+ $this->statementType = SqlFieldsQuery::STATEMENT_TYPE_ANY;
+ $this->enforceJoinOrder = false;
+ $this->collocated = false;
+ $this->lazy = false;
+ $this->includeFieldNames = false;
+ }
+
+ /**
+ * Set schema for the query.
+ *
+ * @param string $schema schema for the query.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setSchema(string $schema): SqlFieldsQuery
+ {
+ $this->schema = $schema;
+ return $this;
+ }
+
+ /**
+ * Set max rows.
+ *
+ * @param int $maxRows max rows.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setMaxRows(int $maxRows): SqlFieldsQuery
+ {
+ $this->maxRows = $maxRows;
+ return $this;
+ }
+
+ /**
+ * Set statement type.
+ *
+ * @param int $type statement type, one of @ref SqlFieldsQueryStatementType constants.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setStatementType(int $type): SqlFieldsQuery
+ {
+ $this->statementType = $type;
+ return $this;
+ }
+
+ /**
+ * Set enforce join order flag.
+ *
+ * @param bool $enforceJoinOrder enforce join order flag: true or false.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setEnforceJoinOrder(bool $enforceJoinOrder): SqlFieldsQuery
+ {
+ $this->enforceJoinOrder = $enforceJoinOrder;
+ return $this;
+ }
+
+ /**
+ * Set collocated flag.
+ *
+ * @param bool $collocated collocated flag: true or false.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setCollocated(bool $collocated): SqlFieldsQuery
+ {
+ $this->collocated = $collocated;
+ return $this;
+ }
+
+ /**
+ * Set lazy query execution flag.
+ *
+ * @param bool $lazy lazy query execution flag: true or false.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setLazy(bool $lazy): SqlFieldsQuery
+ {
+ $this->lazy = $lazy;
+ return $this;
+ }
+
+ /**
+ * Set include field names flag.
+ *
+ * @param bool $includeFieldNames include field names flag: true or false.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setIncludeFieldNames(bool $includeFieldNames): SqlFieldsQuery
+ {
+ $this->includeFieldNames = $includeFieldNames;
+ return $this;
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function write(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ BinaryCommunicator::writeString($buffer, $this->schema);
+ $buffer->writeInteger($this->pageSize);
+ $buffer->writeInteger($this->maxRows);
+ BinaryCommunicator::writeString($buffer, $this->sql);
+ $this->writeArgs($communicator, $buffer);
+ $buffer->writeByte($this->statementType);
+ $buffer->writeBoolean($this->distributedJoins);
+ $buffer->writeBoolean($this->local);
+ $buffer->writeBoolean($this->replicatedOnly);
+ $buffer->writeBoolean($this->enforceJoinOrder);
+ $buffer->writeBoolean($this->collocated);
+ $buffer->writeBoolean($this->lazy);
+ $buffer->writeLong($this->timeout);
+ $buffer->writeBoolean($this->includeFieldNames);
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function getCursor(BinaryCommunicator $communicator, MessageBuffer $payload, $keyType = null, $valueType = null): CursorInterface
+ {
+ $cursor = new SqlFieldsCursor($communicator, $payload);
+ $cursor->readFieldNames($payload, $this->includeFieldNames);
+ return $cursor;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Query/SqlQuery.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Query/SqlQuery.php b/modules/platforms/php/src/Apache/Ignite/Query/SqlQuery.php
new file mode 100644
index 0000000..50cc08b
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Query/SqlQuery.php
@@ -0,0 +1,225 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Query;
+
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\ClientOperation;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+use Apache\Ignite\Internal\Query\Cursor;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+
+/**
+ * Class representing an SQL query which returns the whole cache entries (key-value pairs).
+ */
+class SqlQuery extends Query
+{
+ private $args;
+ private $argTypes;
+ protected $sql;
+ protected $type;
+ protected $distributedJoins;
+ protected $replicatedOnly;
+ protected $timeout;
+
+ /**
+ * Public constructor.
+ *
+ * Requires name of a type (or SQL table) and SQL query string to be specified.
+ * Other SQL query settings have the following defaults:
+ * <pre>
+ * SQL Query setting : Default value
+ * Local query flag : false
+ * Cursor page size : 1024
+ * Query arguments : not specified
+ * Distributed joins flag : false
+ * Replicated only flag : false
+ * Timeout : 0 (disabled)
+ * </pre>
+ * Every setting may be changed using set methods.
+ *
+ * @param string $type name of a type or SQL table.
+ * @param string $sql SQL query string.
+ *
+ * @throws ClientException if error.
+ */
+ public function __construct(?string $type, string $sql)
+ {
+ parent::__construct(ClientOperation::QUERY_SQL);
+ $this->setType($type);
+ $this->setSql($sql);
+ $this->args = null;
+ $this->argTypes = null;
+ $this->distributedJoins = false;
+ $this->replicatedOnly = false;
+ $this->timeout = 0;
+ }
+
+ /**
+ * Set name of a type or SQL table.
+ *
+ * @param string $type name of a type or SQL table.
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ *
+ * @throws ClientException if error.
+ */
+ public function setType(?string $type): SqlQuery
+ {
+ if ($this instanceof SqlFieldsQuery) {
+ ArgumentChecker::invalidArgument($type, 'type', SqlFieldsQuery::class);
+ }
+ $this->type = $type;
+ return $this;
+ }
+
+ /**
+ * Set SQL query string.
+ *
+ * @param string $sql SQL query string.
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ */
+ public function setSql(string $sql): SqlQuery
+ {
+ $this->sql = $sql;
+ return $this;
+ }
+
+ /**
+ * Set query arguments.
+ *
+ * Type of any argument may be specified using setArgTypes() method.
+ * If type of an argument is not specified then during operations the Ignite client
+ * will try to make automatic mapping between PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * @param mixed ...$args Query arguments.
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ */
+ public function setArgs(...$args): SqlQuery
+ {
+ $this->args = $args;
+ return $this;
+ }
+
+ /**
+ * Specifies types of query arguments.
+ *
+ * Query arguments itself are set using setArgs() method.
+ * By default, a type of every argument is not specified that means during operations the Ignite client
+ * will try to make automatic mapping between PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * @param int|ObjectType|null ...$argTypes types of Query arguments.
+ * The order of types must follow the order of arguments in the setArgs() method.
+ * A type of every argument can be:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (or not specified) that means the type is not specified
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ *
+ * @throws ClientException if error.
+ */
+ public function setArgTypes(...$argTypes): SqlQuery
+ {
+ foreach ($argTypes as $argType) {
+ BinaryUtils::checkObjectType($argType, 'argTypes');
+ }
+ $this->argTypes = $argTypes;
+ return $this;
+ }
+
+ /**
+ * Set distributed joins flag.
+ *
+ * @param bool $distributedJoins distributed joins flag: true or false.
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ */
+ public function setDistributedJoins(bool $distributedJoins): SqlQuery
+ {
+ $this->distributedJoins = $distributedJoins;
+ return $this;
+ }
+
+ /**
+ * Set replicated only flag.
+ *
+ * @param bool $replicatedOnly replicated only flag: true or false.
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ */
+ public function setReplicatedOnly(bool $replicatedOnly): SqlQuery
+ {
+ $this->replicatedOnly = $replicatedOnly;
+ return $this;
+ }
+
+ /**
+ * Set timeout.
+ *
+ * @param float $timeout timeout value in milliseconds.
+ * Must be non-negative. Zero value disables timeout.
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ */
+ public function setTimeout(float $timeout): SqlQuery
+ {
+ $this->timeout = $timeout;
+ return $this;
+ }
+
+ protected function writeArgs(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ $argsLength = $this->args ? count($this->args) : 0;
+ $buffer->writeInteger($argsLength);
+ if ($argsLength > 0) {
+ for ($i = 0; $i < $argsLength; $i++) {
+ $argType = $this->argTypes && $i < count($this->argTypes) ? $this->argTypes[$i] : null;
+ $communicator->writeObject($buffer, $this->args[$i], $argType);
+ }
+ }
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function write(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ BinaryCommunicator::writeString($buffer, $this->type);
+ BinaryCommunicator::writeString($buffer, $this->sql);
+ $this->writeArgs($communicator, $buffer);
+ $buffer->writeBoolean($this->distributedJoins);
+ $buffer->writeBoolean($this->local);
+ $buffer->writeBoolean($this->replicatedOnly);
+ $buffer->writeInteger($this->pageSize);
+ $buffer->writeLong($this->timeout);
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function getCursor(BinaryCommunicator $communicator, MessageBuffer $payload, $keyType = null, $valueType = null): CursorInterface
+ {
+ $cursor = new Cursor($communicator, ClientOperation::QUERY_SQL_CURSOR_GET_PAGE, $payload, $keyType, $valueType);
+ $cursor->readId($payload);
+ return $cursor;
+ }
+}
[9/9] ignite git commit: IGNITE-7783: PHP thin client
Posted by is...@apache.org.
IGNITE-7783: PHP thin client
This closes #4649
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/7d3ea115
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/7d3ea115
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/7d3ea115
Branch: refs/heads/master
Commit: 7d3ea1155fa26b56a814b0b236b3a343a8520694
Parents: 1415c61
Author: Igor Sapego <is...@apache.org>
Authored: Tue Oct 9 16:57:05 2018 +0300
Committer: Igor Sapego <is...@apache.org>
Committed: Tue Oct 9 16:57:05 2018 +0300
----------------------------------------------------------------------
modules/platforms/php/.gitignore | 2 +
modules/platforms/php/README.md | 37 +
modules/platforms/php/api_docs/Doxyfile | 2472 ++++++++++++++++++
modules/platforms/php/composer.json | 27 +
.../platforms/php/examples/AuthTlsExample.php | 129 +
.../php/examples/CachePutGetExample.php | 184 ++
.../platforms/php/examples/FailoverExample.php | 67 +
modules/platforms/php/examples/SqlExample.php | 237 ++
.../php/examples/SqlQueryEntriesExample.php | 127 +
modules/platforms/php/examples/certs/ca.pem | 32 +
modules/platforms/php/examples/certs/client.pem | 81 +
.../platforms/php/examples/certs/keystore.jks | Bin 0 -> 3828 bytes
.../platforms/php/examples/certs/truststore.jks | Bin 0 -> 1477 bytes
.../Apache/Ignite/Cache/CacheConfiguration.php | 1011 +++++++
.../php/src/Apache/Ignite/Cache/CacheEntry.php | 60 +
.../src/Apache/Ignite/Cache/CacheInterface.php | 379 +++
.../Ignite/Cache/CacheKeyConfiguration.php | 107 +
.../php/src/Apache/Ignite/Cache/QueryEntity.php | 315 +++
.../php/src/Apache/Ignite/Cache/QueryField.php | 279 ++
.../php/src/Apache/Ignite/Cache/QueryIndex.php | 191 ++
.../platforms/php/src/Apache/Ignite/Client.php | 243 ++
.../src/Apache/Ignite/ClientConfiguration.php | 294 +++
.../php/src/Apache/Ignite/Data/BinaryObject.php | 469 ++++
.../php/src/Apache/Ignite/Data/Date.php | 84 +
.../php/src/Apache/Ignite/Data/EnumItem.php | 155 ++
.../php/src/Apache/Ignite/Data/Time.php | 58 +
.../php/src/Apache/Ignite/Data/Timestamp.php | 64 +
.../Apache/Ignite/Exception/ClientException.php | 35 +
.../Ignite/Exception/NoConnectionException.php | 35 +
.../Ignite/Exception/OperationException.php | 35 +
.../OperationStatusUnknownException.php | 35 +
.../Internal/Binary/BinaryCommunicator.php | 490 ++++
.../Ignite/Internal/Binary/BinaryField.php | 78 +
.../Internal/Binary/BinaryObjectField.php | 113 +
.../Ignite/Internal/Binary/BinarySchema.php | 145 +
.../Ignite/Internal/Binary/BinaryType.php | 233 ++
.../Internal/Binary/BinaryTypeBuilder.php | 207 ++
.../Internal/Binary/BinaryTypeStorage.php | 123 +
.../Ignite/Internal/Binary/BinaryUtils.php | 438 ++++
.../Ignite/Internal/Binary/ClientOperation.php | 64 +
.../Ignite/Internal/Binary/MessageBuffer.php | 307 +++
.../Apache/Ignite/Internal/Binary/Request.php | 85 +
.../Apache/Ignite/Internal/Binary/TypeInfo.php | 312 +++
.../php/src/Apache/Ignite/Internal/Cache.php | 387 +++
.../Connection/ClientFailoverSocket.php | 134 +
.../Ignite/Internal/Connection/ClientSocket.php | 247 ++
.../Internal/Connection/ProtocolVersion.php | 82 +
.../src/Apache/Ignite/Internal/Query/Cursor.php | 166 ++
.../Ignite/Internal/Query/SqlFieldsCursor.php | 75 +
.../Ignite/Internal/Utils/ArgumentChecker.php | 87 +
.../src/Apache/Ignite/Internal/Utils/Logger.php | 62 +
.../src/Apache/Ignite/Query/CursorInterface.php | 56 +
.../php/src/Apache/Ignite/Query/Query.php | 70 +
.../php/src/Apache/Ignite/Query/ScanQuery.php | 88 +
.../Ignite/Query/SqlFieldsCursorInterface.php | 82 +
.../src/Apache/Ignite/Query/SqlFieldsQuery.php | 206 ++
.../php/src/Apache/Ignite/Query/SqlQuery.php | 225 ++
.../Apache/Ignite/Type/CollectionObjectType.php | 142 +
.../Apache/Ignite/Type/ComplexObjectType.php | 165 ++
.../src/Apache/Ignite/Type/MapObjectType.php | 123 +
.../src/Apache/Ignite/Type/ObjectArrayType.php | 68 +
.../php/src/Apache/Ignite/Type/ObjectType.php | 442 ++++
.../platforms/php/tests/BinaryObjectTest.php | 196 ++
.../php/tests/CacheKeyValueOpsTest.php | 763 ++++++
modules/platforms/php/tests/CachePutGetTest.php | 646 +++++
modules/platforms/php/tests/CacheTest.php | 240 ++
.../platforms/php/tests/ComplexObjectTest.php | 428 +++
modules/platforms/php/tests/ScanQueryTest.php | 167 ++
.../platforms/php/tests/SqlFieldsQueryTest.php | 200 ++
modules/platforms/php/tests/SqlQueryTest.php | 204 ++
modules/platforms/php/tests/TestConfig.php | 37 +
modules/platforms/php/tests/TestingHelper.php | 363 +++
.../tests/examples/ExecuteAuthTlsExample.php | 36 +
.../php/tests/examples/ExecuteExamples.php | 61 +
74 files changed, 16087 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/.gitignore
----------------------------------------------------------------------
diff --git a/modules/platforms/php/.gitignore b/modules/platforms/php/.gitignore
new file mode 100644
index 0000000..4f4acd3
--- /dev/null
+++ b/modules/platforms/php/.gitignore
@@ -0,0 +1,2 @@
+vendor/
+composer.lock
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/README.md
----------------------------------------------------------------------
diff --git a/modules/platforms/php/README.md b/modules/platforms/php/README.md
new file mode 100644
index 0000000..d6cd51d
--- /dev/null
+++ b/modules/platforms/php/README.md
@@ -0,0 +1,37 @@
+# PHP Thin Client #
+
+## Installation ##
+
+The client requires PHP version 7.2 or higher (http://php.net/manual/en/install.php) and Composer Dependency Manager (https://getcomposer.org/download/).
+
+The client additionally requires PHP Multibyte String extension. Depending on you PHP configuration you may need to additionally install/configure it (http://php.net/manual/en/mbstring.installation.php)
+
+### Installation from the PHP Package Repository ###
+
+Run from your application root
+```
+composer require apache/apache-ignite-client
+```
+
+To use the client in your application, include `vendor/autoload.php` file, generated by Composer, to your source code, eg.
+```
+require_once __DIR__ . '/vendor/autoload.php';
+```
+
+### Installation from Sources ###
+
+1. Download Ignite sources to `local_ignite_path`
+2. Go to `local_ignite_path/modules/platforms/php` folder
+3. Execute `composer install --no-dev` command
+
+```bash
+cd local_ignite_path/modules/platforms/php
+composer install --no-dev
+```
+
+To use the client in your application, include `vendor/autoload.php` file, generated by Composer, to your source code, eg.
+```
+require_once "<local_ignite_path>/vendor/autoload.php";
+```
+
+For more information, see [Apache Ignite PHP Thin Client documentation](https://apacheignite.readme.io/docs/php-thin-client).
[5/9] ignite git commit: IGNITE-7783: PHP thin client
Posted by is...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryCommunicator.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryCommunicator.php b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryCommunicator.php
new file mode 100644
index 0000000..520063c
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryCommunicator.php
@@ -0,0 +1,490 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Binary;
+
+use Ds\Map;
+use Ds\Set;
+use Brick\Math\BigDecimal;
+use Brick\Math\BigInteger;
+use Apache\Ignite\Internal\Connection\ClientFailoverSocket;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Type\CollectionObjectType;
+use Apache\Ignite\Type\ComplexObjectType;
+use Apache\Ignite\Type\MapObjectType;
+use Apache\Ignite\Data\BinaryObject;
+use Apache\Ignite\Data\Date;
+use Apache\Ignite\Data\EnumItem;
+use Apache\Ignite\Data\Time;
+use Apache\Ignite\Data\Timestamp;
+use Apache\Ignite\Exception\ClientException;
+
+class BinaryCommunicator
+{
+ private $socket;
+ private $typeStorage;
+
+ public function __construct(ClientFailoverSocket $socket)
+ {
+ $this->socket = $socket;
+ $this->typeStorage = new BinaryTypeStorage($this);
+ }
+
+ public function send(int $opCode, ?callable $payloadWriter, callable $payloadReader = null): void
+ {
+ $this->socket->send($opCode, $payloadWriter, $payloadReader);
+ }
+
+ public function getTypeStorage(): BinaryTypeStorage
+ {
+ return $this->typeStorage;
+ }
+
+ public static function readString(MessageBuffer $buffer): ?string
+ {
+ $typeCode = $buffer->readByte();
+ BinaryUtils::checkTypesCompatibility(ObjectType::STRING, $typeCode);
+ if ($typeCode === ObjectType::NULL) {
+ return null;
+ }
+ return $buffer->readString();
+ }
+
+ public static function writeString(MessageBuffer $buffer, ?string $str): void
+ {
+ if ($str === null) {
+ $buffer->writeByte(ObjectType::NULL);
+ } else {
+ $buffer->writeByte(ObjectType::STRING);
+ $buffer->writeString($str);
+ }
+ }
+
+ public function readObject(MessageBuffer $buffer, $expectedType = null)
+ {
+ $typeCode = $buffer->readByte();
+ BinaryUtils::checkTypesCompatibility($expectedType, $typeCode);
+ return $this->readTypedObject($buffer, $typeCode, $expectedType);
+ }
+
+ public function readStringArray(MessageBuffer $buffer): array
+ {
+ return $this->readTypedObject($buffer, ObjectType::STRING_ARRAY);
+ }
+
+ public function writeObject(MessageBuffer $buffer, $object, $objectType = null, bool $writeObjectType = true): void
+ {
+ BinaryUtils::checkCompatibility($object, $objectType);
+ if ($object === null) {
+ $buffer->writeByte(ObjectType::NULL);
+ return;
+ }
+
+ $objectType = $objectType ? $objectType : BinaryUtils::calcObjectType($object);
+ $objectTypeCode = BinaryUtils::getTypeCode($objectType);
+
+ if ($writeObjectType) {
+ $buffer->writeByte($objectTypeCode);
+ }
+ switch ($objectTypeCode) {
+ case ObjectType::BYTE:
+ case ObjectType::SHORT:
+ case ObjectType::INTEGER:
+ case ObjectType::LONG:
+ case ObjectType::FLOAT:
+ case ObjectType::DOUBLE:
+ $buffer->writeNumber($object, $objectTypeCode);
+ break;
+ case ObjectType::CHAR:
+ $buffer->writeChar($object);
+ break;
+ case ObjectType::BOOLEAN:
+ $buffer->writeBoolean($object);
+ break;
+ case ObjectType::STRING:
+ $buffer->writeString($object);
+ break;
+ case ObjectType::UUID:
+ $this->writeUUID($buffer, $object);
+ break;
+ case ObjectType::DATE:
+ $this->writeDate($buffer, $object);
+ break;
+ case ObjectType::ENUM:
+ $this->writeEnum($buffer, $object);
+ break;
+ case ObjectType::DECIMAL:
+ $this->writeDecimal($buffer, $object);
+ break;
+ case ObjectType::TIME:
+ $this->writeTime($buffer, $object);
+ break;
+ case ObjectType::TIMESTAMP:
+ $this->writeTimestamp($buffer, $object);
+ break;
+ case ObjectType::BYTE_ARRAY:
+ case ObjectType::SHORT_ARRAY:
+ case ObjectType::INTEGER_ARRAY:
+ case ObjectType::LONG_ARRAY:
+ case ObjectType::FLOAT_ARRAY:
+ case ObjectType::DOUBLE_ARRAY:
+ case ObjectType::CHAR_ARRAY:
+ case ObjectType::BOOLEAN_ARRAY:
+ case ObjectType::STRING_ARRAY:
+ case ObjectType::UUID_ARRAY:
+ case ObjectType::DATE_ARRAY:
+ case ObjectType::OBJECT_ARRAY:
+ case ObjectType::ENUM_ARRAY:
+ case ObjectType::DECIMAL_ARRAY:
+ case ObjectType::TIMESTAMP_ARRAY:
+ case ObjectType::TIME_ARRAY:
+ $this->writeArray($buffer, $object, $objectType, $objectTypeCode);
+ break;
+ case ObjectType::COLLECTION:
+ $this->writeCollection($buffer, $object, $objectType);
+ break;
+ case ObjectType::MAP:
+ $this->writeMap($buffer, $object, $objectType);
+ break;
+ case ObjectType::BINARY_OBJECT:
+ $this->writeBinaryObject($buffer, $object);
+ break;
+ case ObjectType::COMPLEX_OBJECT:
+ $this->writeComplexObject($buffer, $object, $objectType);
+ break;
+ default:
+ BinaryUtils::unsupportedType($objectType);
+ }
+ }
+
+ public function readTypedObject(MessageBuffer $buffer, int $objectTypeCode, $expectedType = null)
+ {
+ switch ($objectTypeCode) {
+ case ObjectType::BYTE:
+ case ObjectType::SHORT:
+ case ObjectType::INTEGER:
+ case ObjectType::LONG:
+ case ObjectType::FLOAT:
+ case ObjectType::DOUBLE:
+ return $buffer->readNumber($objectTypeCode);
+ case ObjectType::CHAR:
+ return $buffer->readChar();
+ case ObjectType::BOOLEAN:
+ return $buffer->readBoolean();
+ case ObjectType::STRING:
+ return $buffer->readString();
+ case ObjectType::UUID:
+ return $this->readUUID($buffer);
+ case ObjectType::DATE:
+ return $this->readDate($buffer);
+ case ObjectType::ENUM:
+ case ObjectType::BINARY_ENUM:
+ return $this->readEnum($buffer);
+ case ObjectType::DECIMAL:
+ return $this->readDecimal($buffer);
+ case ObjectType::TIME:
+ return $this->readTime($buffer);
+ case ObjectType::TIMESTAMP:
+ return $this->readTimestamp($buffer);
+ case ObjectType::BYTE_ARRAY:
+ case ObjectType::SHORT_ARRAY:
+ case ObjectType::INTEGER_ARRAY:
+ case ObjectType::LONG_ARRAY:
+ case ObjectType::FLOAT_ARRAY:
+ case ObjectType::DOUBLE_ARRAY:
+ case ObjectType::CHAR_ARRAY:
+ case ObjectType::BOOLEAN_ARRAY:
+ case ObjectType::STRING_ARRAY:
+ case ObjectType::UUID_ARRAY:
+ case ObjectType::DATE_ARRAY:
+ case ObjectType::OBJECT_ARRAY:
+ case ObjectType::ENUM_ARRAY:
+ case ObjectType::DECIMAL_ARRAY:
+ case ObjectType::TIMESTAMP_ARRAY:
+ case ObjectType::TIME_ARRAY:
+ return $this->readArray($buffer, $objectTypeCode, $expectedType);
+ case ObjectType::COLLECTION:
+ return $this->readCollection($buffer, $expectedType);
+ case ObjectType::MAP:
+ return $this->readMap($buffer, $expectedType);
+ case ObjectType::BINARY_OBJECT:
+ return $this->readBinaryObject($buffer, $expectedType);
+ case ObjectType::NULL:
+ return null;
+ case ObjectType::COMPLEX_OBJECT:
+ return $this->readComplexObject($buffer, $expectedType);
+ default:
+ BinaryUtils::unsupportedType($objectTypeCode);
+ }
+ return null;
+ }
+
+ private function readDate(MessageBuffer $buffer): Date
+ {
+ return new Date($buffer->readLong());
+ }
+
+ private function readTime(MessageBuffer $buffer): Time
+ {
+ return new Time($buffer->readLong());
+ }
+
+ private function readTimestamp(MessageBuffer $buffer): Timestamp
+ {
+ return new Timestamp($buffer->readLong(), $buffer->readInteger());
+ }
+
+ private function readUUID(MessageBuffer $buffer): array
+ {
+ $result = [];
+ for ($i = 0; $i < BinaryUtils::getSize(ObjectType::UUID); $i++) {
+ array_push($result, $buffer->readByte(false));
+ }
+ return $result;
+ }
+
+ private function readEnum(MessageBuffer $buffer): EnumItem
+ {
+ $enumItem = new EnumItem($buffer->readInteger());
+ $ordinal = $buffer->readInteger();
+ $enumItem->setOrdinal($ordinal);
+ $type = $this->typeStorage->getType($enumItem->getTypeId());
+ if (!$type->isEnum() || !$type->getEnumValues() || count($type->getEnumValues()) <= $ordinal) {
+ BinaryUtils::serializationError(false, 'EnumItem can not be deserialized: type mismatch');
+ }
+ $enumValues = $type->getEnumValues();
+ $enumItem->setName($enumValues[$ordinal][0]);
+ $enumItem->setValue($enumValues[$ordinal][1]);
+ return $enumItem;
+ }
+
+ private function readDecimal(MessageBuffer $buffer): BigDecimal
+ {
+ $scale = $buffer->readInteger();
+ $value = $buffer->readString(false);
+ $isNegative = (ord($value[0]) & 0x80) !== 0;
+ if ($isNegative) {
+ $value[0] = chr(ord($value[0]) & 0x7F);
+ }
+ $hexValue = '';
+ for ($i = 0; $i < strlen($value); $i++) {
+ $hex = dechex(ord($value[$i]));
+ if (strlen($hex) < 2) {
+ $hex = str_repeat('0', 2 - strlen($hex)) . $hex;
+ }
+ $hexValue .= $hex;
+ }
+ $result = BigDecimal::ofUnscaledValue(BigInteger::parse($hexValue, 16), $scale >= 0 ? $scale : 0);
+ if ($isNegative) {
+ $result = $result->negated();
+ }
+ if ($scale < 0) {
+ $result = $result->multipliedBy((BigInteger::of(10))->power(-$scale));
+ }
+ return $result;
+ }
+
+ private function readArray(MessageBuffer $buffer, int $arrayTypeCode, $arrayType): array
+ {
+ if ($arrayTypeCode === ObjectType::OBJECT_ARRAY) {
+ $buffer->readInteger();
+ }
+ $length = $buffer->readInteger();
+ $elementType = BinaryUtils::getArrayElementType($arrayType ? $arrayType : $arrayTypeCode);
+ $keepElementType = $elementType === null ? true : TypeInfo::getTypeInfo($arrayTypeCode)->keepElementType();
+ $result = array();
+ for ($i = 0; $i < $length; $i++) {
+ array_push(
+ $result,
+ $keepElementType ?
+ $this->readObject($buffer, $elementType) :
+ $this->readTypedObject($buffer, $elementType));
+ }
+ return $result;
+ }
+
+ private function readCollection(MessageBuffer $buffer, CollectionObjectType $expectedColType = null)
+ {
+ $size = $buffer->readInteger();
+ $subType = $buffer->readByte();
+ $isSet = CollectionObjectType::isSet($subType);
+ $result = $isSet ? new Set() : [];
+ for ($i = 0; $i < $size; $i++) {
+ $element = $this->readObject($buffer, $expectedColType ? $expectedColType->getElementType() : null);
+ if ($isSet) {
+ $result->add($element);
+ } else {
+ array_push($result, $element);
+ }
+ }
+ return $result;
+ }
+
+ private function readMap(MessageBuffer $buffer, MapObjectType $expectedMapType = null): Map
+ {
+ $size = $buffer->readInteger();
+ // map sub-type
+ $buffer->readByte();
+ $result = new Map();
+ $result->allocate($size);
+ for ($i = 0; $i < $size; $i++) {
+ $key = $this->readObject($buffer, $expectedMapType ? $expectedMapType->getKeyType() : null);
+ $value = $this->readObject($buffer, $expectedMapType ? $expectedMapType->getValueType() : null);
+ $result->put($key, $value);
+ }
+ return $result;
+ }
+
+ private function readBinaryObject(MessageBuffer $buffer, ?ComplexObjectType $expectedType): object
+ {
+ $size = $buffer->readInteger();
+ $startPos = $buffer->getPosition();
+ $buffer->setPosition($startPos + $size);
+ $offset = $buffer->readInteger();
+ $endPos = $buffer->getPosition();
+ $buffer->setPosition($startPos + $offset);
+ $result = $this->readObject($buffer, $expectedType);
+ $buffer->setPosition($endPos);
+ return $result;
+ }
+
+ private function readComplexObject(MessageBuffer $buffer, ?ComplexObjectType $expectedType): object
+ {
+ $buffer->setPosition($buffer->getPosition() - 1);
+ $binaryObject = BinaryObject::fromBuffer($this, $buffer);
+ return $expectedType ? $binaryObject->toObject($expectedType) : $binaryObject;
+ }
+
+ private function writeDate(MessageBuffer $buffer, Date $date): void
+ {
+ $buffer->writeLong($date->getMillis());
+ }
+
+ private function writeTime(MessageBuffer $buffer, Time $time): void
+ {
+ $buffer->writeLong($time->getMillis());
+ }
+
+ private function writeTimestamp(MessageBuffer $buffer, Timestamp $timestamp): void
+ {
+ $buffer->writeLong($timestamp->getMillis());
+ $buffer->writeInteger($timestamp->getNanos());
+ }
+
+ private function writeUUID(MessageBuffer $buffer, array $value): void
+ {
+ for ($i = 0; $i < count($value); $i++) {
+ $buffer->writeByte($value[$i], false);
+ }
+ }
+
+ private function writeEnum(MessageBuffer $buffer, EnumItem $enumValue): void
+ {
+ $buffer->writeInteger($enumValue->getTypeId());
+ if ($enumValue->getOrdinal() !== null) {
+ $buffer->writeInteger($enumValue->getOrdinal());
+ return;
+ } elseif ($enumValue->getName() !== null || $enumValue->getValue() !== null) {
+ $type = $this->typeStorage->getType($enumValue->getTypeId());
+ if ($type && $type->isEnum()) {
+ $enumValues = $type->getEnumValues();
+ if ($enumValues) {
+ for ($i = 0; $i < count($enumValues); $i++) {
+ if ($enumValue->getName() === $enumValues[$i][0] ||
+ $enumValue->getValue() === $enumValues[$i][1]) {
+ $buffer->writeInteger($i);
+ return;
+ }
+ }
+ }
+ }
+ }
+ ArgumentChecker::illegalArgument('Proper ordinal, name or value must be specified for EnumItem');
+ }
+
+ private function writeDecimal(MessageBuffer $buffer, BigDecimal $decimal): void
+ {
+ $scale = $decimal->getScale();
+ $isNegative = $decimal->isNegative();
+ $hexValue = $decimal->getUnscaledValue()->abs()->toBase(16);
+ $hexValue = ((strlen($hexValue) % 2 !== 0) ? '000' : '00') . $hexValue;
+ if ($isNegative) {
+ $hexValue[0] = '8';
+ }
+ $value = '';
+ for ($i = 0; $i < strlen($hexValue); $i += 2) {
+ $value .= chr(hexdec(substr($hexValue, $i, 2)));
+ }
+ $buffer->writeInteger($scale);
+ $buffer->writeString($value, false);
+ }
+
+ private function writeArray(MessageBuffer $buffer, array $array, $arrayType, int $arrayTypeCode): void
+ {
+ $elementType = BinaryUtils::getArrayElementType($arrayType);
+ $keepElementType = !$elementType || TypeInfo::getTypeInfo($arrayTypeCode)->keepElementType();
+ if ($arrayTypeCode === ObjectType::OBJECT_ARRAY) {
+ $typeId = -1;
+ if ($elementType instanceof ComplexObjectType) {
+ $typeName = BinaryTypeBuilder::calcTypeName($elementType, count($array) > 0 ? $array[0] : null);
+ if ($typeName) {
+ $typeId = BinaryType::calculateId($typeName);
+ }
+ }
+ $buffer->writeInteger($typeId);
+ }
+ $buffer->writeInteger(count($array));
+ foreach ($array as $elem) {
+ $this->writeObject($buffer, $elem, $elementType, $keepElementType);
+ }
+ }
+
+ private function writeCollection(MessageBuffer $buffer, $collection, CollectionObjectType $collectionType): void
+ {
+ $buffer->writeInteger($collection instanceof Set ? $collection->count() : count($collection));
+ $buffer->writeByte($collectionType->getSubType());
+ foreach ($collection as $element) {
+ $this->writeObject($buffer, $element, $collectionType->getElementType());
+ }
+ }
+
+ private function writeMap(MessageBuffer $buffer, $map, MapObjectType $mapType): void
+ {
+ if (!($map instanceof Map)) {
+ $map = new Map($map);
+ }
+ $buffer->writeInteger($map->count());
+ $buffer->writeByte($mapType->getSubType());
+ foreach ($map->pairs() as $pair) {
+ $this->writeObject($buffer, $pair->key, $mapType->getKeyType());
+ $this->writeObject($buffer, $pair->value, $mapType->getValueType());
+ }
+ }
+
+ private function writeBinaryObject(MessageBuffer $buffer, BinaryObject $binaryObject): void
+ {
+ $buffer->setPosition($buffer->getPosition() - 1);
+ $binaryObject->write($this, $buffer);
+ }
+
+ private function writeComplexObject(MessageBuffer $buffer, object $object, ?ComplexObjectType $objectType): void
+ {
+ $this->writeBinaryObject($buffer, BinaryObject::fromObject($object, $objectType));
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryField.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryField.php b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryField.php
new file mode 100644
index 0000000..8fdeab3
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryField.php
@@ -0,0 +1,78 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Binary;
+
+class BinaryField
+{
+ private $name;
+ private $id;
+ private $typeCode;
+
+ public function __construct(string $name = null, int $typeCode = 0)
+ {
+ $this->name = $name;
+ $this->id = BinaryField::calculateId($name);
+ $this->typeCode = $typeCode;
+ }
+
+ public static function calculateId(?string $name): int
+ {
+ return BinaryUtils::hashCodeLowerCase($name);
+ }
+
+ public function getId(): int
+ {
+ return $this->id;
+ }
+
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ public function getTypeCode(): int
+ {
+ return $this->typeCode;
+ }
+
+ public function isValid(): bool
+ {
+ return $this->name !== null;
+ }
+
+ public function write(MessageBuffer $buffer): void
+ {
+ // field name
+ BinaryCommunicator::writeString($buffer, $this->name);
+ // type code
+ $buffer->writeInteger($this->typeCode);
+ // field id
+ $buffer->writeInteger($this->id);
+ }
+
+ public function read(MessageBuffer $buffer): void
+ {
+ // field name
+ $this->name = BinaryCommunicator::readString($buffer);
+ // type code
+ $this->typeCode = $buffer->readInteger();
+ // field id
+ $this->id = $buffer->readInteger();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryObjectField.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryObjectField.php b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryObjectField.php
new file mode 100644
index 0000000..cbe24d2
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryObjectField.php
@@ -0,0 +1,113 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Binary;
+
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Exception\ClientException;
+
+class BinaryObjectField
+{
+ private $name;
+ private $id;
+ private $value;
+ private $type;
+ private $typeCode;
+
+ private $communicator;
+ private $buffer;
+ private $offset;
+ private $length;
+
+ public function __construct(?string $name, $value = null, $type = null)
+ {
+ $this->name = $name;
+ $this->id = BinaryField::calculateId($name);
+ $this->value = $value;
+ $this->type = $type;
+ if (!$type && $value !== null) {
+ $this->type = BinaryUtils::calcObjectType($value);
+ }
+ $this->typeCode = $this->type ? BinaryUtils::getTypeCode($this->type) : 0;
+ }
+
+ public function getId(): int
+ {
+ return $this->id;
+ }
+
+ public function getTypeCode(): int
+ {
+ return $this->typeCode;
+ }
+
+ public function getValue($type = null)
+ {
+ if ($this->buffer && ($this->value === null || $this->type !== $type)) {
+ $this->buffer->setPosition($this->offset);
+ $this->value = $this->communicator->readObject($this->buffer, $type);
+ $this->type = $type;
+ }
+ return $this->value;
+ }
+
+ public static function fromBuffer(BinaryCommunicator $communicator, MessageBuffer $buffer, int $offset, int $length, int $id): BinaryObjectField
+ {
+ $result = new BinaryObjectField(null);
+ $result->id = $id;
+ $result->communicator = $communicator;
+ $result->buffer = $buffer;
+ $result->offset = $offset;
+ $result->length = $length;
+ return $result;
+ }
+
+ public function writeValue(BinaryCommunicator $communicator, MessageBuffer $buffer, int $expectedTypeCode): void
+ {
+ $offset = $buffer->getPosition();
+ if ($this->buffer && $this->communicator === $communicator) {
+ $buffer->writeBuffer($this->buffer, $this->offset, $this->length);
+ } else {
+ if (!$this->value) {
+ $this->getValue($expectedTypeCode);
+ }
+ BinaryUtils::checkCompatibility($this->value, $expectedTypeCode);
+ $communicator->writeObject($buffer, $this->value, $this->type);
+ }
+ $this->communicator = $communicator;
+ $this->buffer = $buffer;
+ $this->length = $buffer->getPosition() - $offset;
+ $this->offset = $offset;
+ }
+
+ public function writeOffset(MessageBuffer $buffer, int $headerStartPos, int $offsetType): void
+ {
+ $buffer->writeNumber($this->offset - $headerStartPos, $offsetType, false);
+ }
+
+ public function getOffsetType(int $headerStartPos): int
+ {
+ $offset = $this->offset - $headerStartPos;
+ if ($offset < TypeInfo::getTypeInfo(ObjectType::BYTE)->getMaxUnsignedValue()) {
+ return ObjectType::BYTE;
+ } elseif ($offset < TypeInfo::getTypeInfo(ObjectType::SHORT)->getMaxUnsignedValue()) {
+ return ObjectType::SHORT;
+ }
+ return ObjectType::INTEGER;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinarySchema.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinarySchema.php b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinarySchema.php
new file mode 100644
index 0000000..cff6ae8
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinarySchema.php
@@ -0,0 +1,145 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Binary;
+
+use Brick\Math\BigInteger;
+use Apache\Ignite\Type\ObjectType;
+
+class BinarySchema
+{
+ /** FNV1 hash offset basis. */
+ const FNV1_OFFSET_BASIS = 0x811C9DC5;
+ /** FNV1 hash prime. */
+ const FNV1_PRIME = 0x01000193;
+
+ private $id;
+ private $fieldIds;
+ private $isValid;
+
+ public function __construct()
+ {
+ $this->id = BinarySchema::FNV1_OFFSET_BASIS;
+ $this->fieldIds = [];
+ $this->isValid = true;
+ }
+
+ public function getId(): int
+ {
+ return $this->id;
+ }
+
+ public function getFieldIds(): array
+ {
+ return array_keys($this->fieldIds);
+ }
+
+ public function finalize(): void
+ {
+ if (!$this->isValid) {
+ $this->id = BinarySchema::FNV1_OFFSET_BASIS;
+ foreach ($this->fieldIds as $key => $value) {
+ BinarySchema::updateSchemaId($key);
+ }
+ $this->isValid = true;
+ }
+ }
+
+ public function cloneSchema(): BinarySchema
+ {
+ $result = new BinarySchema();
+ $result->id = $this->id;
+ $result->fieldIds = [];
+ foreach($this->fieldIds as $key => $value) {
+ $result->fieldIds[$key] = $value;
+ }
+ $result->isValid = $this->isValid;
+ return $result;
+ }
+
+ public function addField(int $fieldId): void
+ {
+ if (!$this->hasField($fieldId)) {
+ $this->fieldIds[$fieldId] = true;
+ if ($this->isValid) {
+ $this->updateSchemaId($fieldId);
+ }
+ }
+ }
+
+ public function removeField(int $fieldId): void
+ {
+ if ($this->hasField($fieldId)) {
+ unset($this->fieldIds[$fieldId]);
+ $this->isValid = false;
+ }
+ }
+
+ public function hasField(int $fieldId): bool
+ {
+ return array_key_exists($fieldId, $this->fieldIds);
+ }
+
+ private function updateSchemaId(int $fieldId): void
+ {
+ $this->updateSchemaIdPart($fieldId & 0xFF);
+ $this->updateSchemaIdPart(($fieldId >> 8) & 0xFF);
+ $this->updateSchemaIdPart(($fieldId >> 16) & 0xFF);
+ $this->updateSchemaIdPart(($fieldId >> 24) & 0xFF);
+ $this->id = BinaryUtils::intVal32($this->id);
+ }
+
+ private function updateSchemaIdPart(int $fieldIdPart): void
+ {
+ $this->id = $this->id ^ $fieldIdPart;
+ if (BinaryUtils::$is32BitInt) {
+ $hexValue = BinaryUtils::getLongHex(BigInteger::of(abs($this->id))->multipliedBy(BinarySchema::FNV1_PRIME), $this->id < 0);
+ $len = strlen($hexValue);
+ $size = TypeInfo::getTypeInfo(ObjectType::INTEGER)->getSize() * 2;
+ $this->id = hexdec($len > $size ? substr($hexValue, $len - $size) : $hexValue);
+ } else {
+ $this->id = $this->id * BinarySchema::FNV1_PRIME;
+ }
+ $this->id &= 0xFFFFFFFF; // Convert to 32bit integer
+ }
+
+ public function write(MessageBuffer $buffer): void
+ {
+ $this->finalize();
+ // schema id
+ $buffer->writeInteger($this->id);
+ // fields count
+ $buffer->writeInteger(count($this->fieldIds));
+ // field ids
+ foreach ($this->fieldIds as $key => $value) {
+ $buffer->writeInteger($key);
+ }
+ }
+
+ public function read(MessageBuffer $buffer): void
+ {
+ // schema id
+ $this->id = $buffer->readInteger();
+ // fields count
+ $fieldsCount = $buffer->readInteger();
+ // field ids
+ for ($i = 0; $i < $fieldsCount; $i++) {
+ $this->fieldIds[$buffer->readInteger()] = true;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryType.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryType.php b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryType.php
new file mode 100644
index 0000000..8cd1c82
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryType.php
@@ -0,0 +1,233 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Binary;
+
+class BinaryType
+{
+ private $name;
+ private $id;
+ private $fields;
+ private $schemas;
+ private $isEnum;
+ private $enumValues;
+
+ public function __construct(?string $name)
+ {
+ $this->name = $name;
+ $this->id = BinaryType::calculateId($name);
+ $this->fields = [];
+ $this->schemas = [];
+ $this->isEnum = false;
+ $this->enumValues = null;
+ }
+
+ public static function calculateId($name)
+ {
+ return BinaryUtils::hashCodeLowerCase($name);
+ }
+
+ public function getId(): int
+ {
+ return $this->id;
+ }
+
+ public function setId(int $id): void
+ {
+ $this->id = $id;
+ }
+
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ public function getFields(): array
+ {
+ return array_values($this->fields);
+ }
+
+ public function getField(int $fieldId): ?BinaryField
+ {
+ return $this->hasField($fieldId) ? $this->fields[$fieldId] : null;
+ }
+
+ public function hasField(int $fieldId): bool
+ {
+ return array_key_exists($fieldId, $this->fields);
+ }
+
+ public function removeField(int $fieldId): void
+ {
+ if ($this->hasField($fieldId)) {
+ unset($this->fields[$fieldId]);
+ }
+ }
+
+ public function setField(BinaryField $field): void
+ {
+ $this->fields[$field->getId()] = $field;
+ }
+
+ public function hasSchema(int $schemaId): bool
+ {
+ return array_key_exists($schemaId, $this->schemas);
+ }
+
+ public function addSchema(BinarySchema $schema): void
+ {
+ if (!$this->hasSchema($schema->getId())) {
+ $this->schemas[$schema->getId()] = $schema;
+ }
+ }
+
+ public function getSchema($schemaId): ?BinarySchema
+ {
+ return $this->hasSchema($schemaId) ? $this->schemas[$schemaId] : null;
+ }
+
+ public function isEnum(): bool
+ {
+ return $this->isEnum;
+ }
+
+ public function getEnumValues(): ?array
+ {
+ return $this->enumValues;
+ }
+
+ public function merge(BinaryType $binaryType, BinarySchema $binarySchema): void
+ {
+ foreach ($binaryType->getFields() as $field) {
+ $fieldId = $field->getId();
+ if ($this->hasField($fieldId)) {
+ if ($this->getField($fieldId)->getTypeCode() !== $field->getTypeCode()) {
+ BinaryUtils::serializationError(
+ true, sprintf('type conflict for field "%s" of complex object type "%s"',
+ $field->getName(), $this->name));
+ }
+ } else {
+ $this->setField($field);
+ }
+ }
+ $this->addSchema($binarySchema);
+ }
+
+ public function cloneType(): BinaryType
+ {
+ $result = new BinaryType(null);
+ $result->name = $this->name;
+ $result->id = $this->id;
+ $result->fields = [];
+ foreach($this->fields as $key => $value) {
+ $result->fields[$key] = $value;
+ }
+ $result->schemas = [];
+ foreach($this->schemas as $key => $value) {
+ $result->schemas[$key] = $value;
+ }
+ $result->isEnum = $this->isEnum;
+ return $result;
+ }
+
+ public function isValid(): bool
+ {
+ foreach ($this->fields as $field) {
+ if (!$field->isValid()) {
+ return false;
+ }
+ }
+ return $this->name !== null;
+ }
+
+ public function write(MessageBuffer $buffer): void
+ {
+ // type id
+ $buffer->writeInteger($this->id);
+ // type name
+ BinaryCommunicator::writeString($buffer, $this->name);
+ // affinity key field name
+ BinaryCommunicator::writeString($buffer, null);
+ // fields count
+ $buffer->writeInteger(count($this->fields));
+ // fields
+ foreach ($this->fields as $field) {
+ $field->write($buffer);
+ }
+ $this->writeEnum($buffer);
+ // schemas count
+ $buffer->writeInteger(count($this->schemas));
+ foreach ($this->schemas as $schema) {
+ $schema->write($buffer);
+ }
+ }
+
+ private function writeEnum(MessageBuffer $buffer): void
+ {
+ $buffer->writeBoolean($this->isEnum);
+ if ($this->isEnum) {
+ $length = $this->enumValues ? count($this->enumValues) : 0;
+ $buffer->writeInteger($length);
+ if ($length > 0) {
+ foreach ($this->enumValues as $key => $value) {
+ BinaryCommunicator::writeString($buffer, $key);
+ $buffer->writeInteger($value);
+ }
+ }
+ }
+ }
+
+ public function read(MessageBuffer $buffer): void
+ {
+ // type id
+ $this->id = $buffer->readInteger();
+ // type name
+ $this->name = BinaryCommunicator::readString($buffer);
+ // affinity key field name
+ BinaryCommunicator::readString($buffer);
+ // fields count
+ $fieldsCount = $buffer->readInteger();
+ // fields
+ for ($i = 0; $i < $fieldsCount; $i++) {
+ $field = new BinaryField();
+ $field->read($buffer);
+ $this->setField($field);
+ }
+ $this->readEnum($buffer);
+ // schemas count
+ $schemasCount = $buffer->readInteger();
+ // schemas
+ for ($i = 0; $i < $schemasCount; $i++) {
+ $schema = new BinarySchema();
+ $schema->read($buffer);
+ $this->addSchema($schema);
+ }
+ }
+
+ private function readEnum(MessageBuffer $buffer): void
+ {
+ $this->isEnum = $buffer->readBoolean();
+ if ($this->isEnum) {
+ $valuesCount = $buffer->readInteger();
+ $this->enumValues = [];
+ for ($i = 0; $i < $valuesCount; $i++) {
+ array_push($this->enumValues, [BinaryCommunicator::readString($buffer), $buffer->readInteger()]);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryTypeBuilder.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryTypeBuilder.php b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryTypeBuilder.php
new file mode 100644
index 0000000..f13eddb
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryTypeBuilder.php
@@ -0,0 +1,207 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Binary;
+
+use Apache\Ignite\Type\ComplexObjectType;
+
+class BinaryTypeBuilder
+{
+ private $type;
+ private $schema;
+ private $fromStorage;
+
+ private function __construct()
+ {
+ $this->type = null;
+ $this->schema = null;
+ $this->fromStorage = false;
+ }
+
+ public static function fromTypeName(string $typeName): BinaryTypeBuilder
+ {
+ $result = new BinaryTypeBuilder();
+ $result->init($typeName);
+ return $result;
+ }
+
+ public static function fromTypeId(BinaryCommunicator $communicator, int $typeId, ?int $schemaId): BinaryTypeBuilder
+ {
+ $result = new BinaryTypeBuilder();
+ $type = $communicator->getTypeStorage()->getType($typeId, $schemaId);
+ if ($type) {
+ $result->type = $type;
+ if ($schemaId !== null) {
+ $result->schema = $type->getSchema($schemaId);
+ if (!$result->schema) {
+ BinaryUtils::serializationError(
+ false,
+ sprintf('schema id "%d" specified for complex object of type "%s" not found', $schemaId, $type->getName()));
+ }
+ $result->fromStorage = true;
+ } else {
+ $result->schema = new BinarySchema();
+ }
+ return $result;
+ }
+ $result->init(null);
+ $result->getType()->setId($typeId);
+ return $result;
+ }
+
+ public static function fromObject(object $object, ComplexObjectType $complexObjectType = null): BinaryTypeBuilder
+ {
+ if ($complexObjectType) {
+ return BinaryTypeBuilder::fromComplexObjectType($complexObjectType, $object);
+ } else {
+ $result = new BinaryTypeBuilder();
+ $result->fromComplexObject(new ComplexObjectType(), $object);
+ return $result;
+ }
+ }
+
+ public static function fromComplexObjectType(ComplexObjectType $complexObjectType, object $object): BinaryTypeBuilder
+ {
+ $result = new BinaryTypeBuilder();
+ $typeInfo = BinaryTypeStorage::getByComplexObjectType($complexObjectType);
+ if ($typeInfo) {
+ $result->type = $typeInfo[0];
+ $result->schema = $typeInfo[1];
+ $result->fromStorage = true;
+ } else {
+ $result->fromComplexObject($complexObjectType, $object);
+ BinaryTypeStorage::setByComplexObjectType($complexObjectType, $result->type, $result->schema);
+ }
+ return $result;
+ }
+
+ public static function calcTypeName(ComplexObjectType $complexObjectType, object $object): string
+ {
+ $typeName = $complexObjectType->getIgniteTypeName();
+ if (!$typeName) {
+ $typeName = $object ? get_class($object) : null;
+ }
+ return $typeName;
+ }
+
+ public function getType(): BinaryType
+ {
+ return $this->type;
+ }
+
+ public function getTypeId(): int
+ {
+ return $this->type->getId();
+ }
+
+ public function getTypeName(): string
+ {
+ return $this->type->getName();
+ }
+
+ public function getSchema(): BinarySchema
+ {
+ return $this->schema;
+ }
+
+ public function getSchemaId(): int
+ {
+ return $this->schema->getId();
+ }
+
+ public function getFields(): array
+ {
+ return $this->type->getFields();
+ }
+
+ public function getField(int $fieldId): ?BinaryField
+ {
+ return $this->type->getField($fieldId);
+ }
+
+ public function setField(string $fieldName, int $fieldTypeCode = 0): void
+ {
+ $fieldId = BinaryField::calculateId($fieldName);
+ if (!$this->type->hasField($fieldId) || !$this->schema->hasField($fieldId) ||
+ $this->type->getField($fieldId)->getTypeCode() !== $fieldTypeCode) {
+ $this->beforeModify();
+ $this->type->setField(new BinaryField($fieldName, $fieldTypeCode));
+ $this->schema->addField($fieldId);
+ }
+ }
+
+ public function removeField(string $fieldName): void
+ {
+ $fieldId = BinaryField::calculateId($fieldName);
+ if ($this->type->hasField($fieldId)) {
+ $this->beforeModify();
+ $this->type->removeField($fieldId);
+ $this->schema->removeField($fieldId);
+ }
+ }
+
+ public function finalize(BinaryCommunicator $communicator): void
+ {
+ $this->schema->finalize();
+ $communicator->getTypeStorage()->addType($this->type, $this->schema);
+ }
+
+ private function fromComplexObject(ComplexObjectType $complexObjectType, object $object): void
+ {
+ $typeName = BinaryTypeBuilder::calcTypeName($complexObjectType, $object);
+ $this->init($typeName);
+ $this->setFields($complexObjectType, $object);
+ }
+
+ private function init(?string $typeName): void
+ {
+ $this->type = new BinaryType($typeName);
+ $this->schema = new BinarySchema();
+ }
+
+ private function beforeModify(): void
+ {
+ if ($this->fromStorage) {
+ $this->type = $this->type->cloneType();
+ $this->schema = $this->schema->cloneSchema();
+ $this->fromStorage = false;
+ }
+ }
+
+ private function setFields(ComplexObjectType $complexObjectType, object $object): void
+ {
+ try {
+ $reflect = new \ReflectionClass($object);
+ $properties = $reflect->getProperties(\ReflectionProperty::IS_PUBLIC);
+ foreach ($properties as $property) {
+ if ($property->isStatic()) {
+ continue;
+ }
+ $fieldName = $property->getName();
+ $fieldType = $complexObjectType->getFieldType($fieldName);
+ if (!$fieldType) {
+ $fieldValue = $property->getValue($object);
+ $fieldType = BinaryUtils::calcObjectType($fieldValue);
+ }
+ $this->setField($fieldName, BinaryUtils::getTypeCode($fieldType));
+ }
+ } catch (\ReflectionException $e) {
+ BinaryUtils::serializationError(true, sprintf('class "%s" does not exist', get_class($object)));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryTypeStorage.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryTypeStorage.php b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryTypeStorage.php
new file mode 100644
index 0000000..05d53cc
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryTypeStorage.php
@@ -0,0 +1,123 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Binary;
+
+use Ds\Map;
+use Apache\Ignite\Type\ComplexObjectType;
+
+class BinaryTypeStorage
+{
+ private $communicator;
+ private $types;
+ private static $complexObjectTypes = null;
+
+ public function __construct(BinaryCommunicator $communicator)
+ {
+ $this->communicator = $communicator;
+ $this->types = [];
+ }
+
+ public function addType(BinaryType $binaryType, BinarySchema $binarySchema): void
+ {
+ $typeId = $binaryType->getId();
+ $schemaId = $binarySchema->getId();
+ $storageType = $this->getStorageType($typeId);
+ if (!$storageType || !$storageType->hasSchema($schemaId)) {
+ $binaryType->addSchema($binarySchema);
+ if (!$storageType) {
+ $this->types[$typeId] = $binaryType;
+ } else {
+ $storageType->merge($binaryType, $binarySchema);
+ }
+ $this->putBinaryType($binaryType);
+ }
+ }
+
+ public function getType(int $typeId, int $schemaId = null): ?BinaryType
+ {
+ $storageType = $this->getStorageType($typeId);
+ if (!$storageType || $schemaId && !$storageType->hasSchema($schemaId)) {
+ $storageType = $this->getBinaryType($typeId);
+ if ($storageType) {
+ $this->types[$storageType->getId()] = $storageType;
+ }
+ }
+ return $storageType;
+ }
+
+ public static function getByComplexObjectType(ComplexObjectType $complexObjectType): ?array
+ {
+ return BinaryTypeStorage::getComplexObjectTypes()->get($complexObjectType, null);
+ }
+
+ public static function setByComplexObjectType(ComplexObjectType $complexObjectType, BinaryType $type, BinarySchema $schema): void
+ {
+ if (!BinaryTypeStorage::getComplexObjectTypes()->hasKey($complexObjectType)) {
+ BinaryTypeStorage::getComplexObjectTypes()->put($complexObjectType, [$type, $schema]);
+ }
+ }
+
+ private static function getComplexObjectTypes(): Map
+ {
+ if (!BinaryTypeStorage::$complexObjectTypes) {
+ BinaryTypeStorage::$complexObjectTypes = new Map();
+ }
+ return BinaryTypeStorage::$complexObjectTypes;
+ }
+
+ private function getBinaryType(int $typeId): ?BinaryType
+ {
+ $binaryType = new BinaryType(null);
+ $binaryType->setId($typeId);
+ $this->communicator->send(
+ ClientOperation::GET_BINARY_TYPE,
+ function (MessageBuffer $payload) use ($typeId)
+ {
+ $payload->writeInteger($typeId);
+ },
+ function (MessageBuffer $payload) use (&$binaryType)
+ {
+ $exist = $payload->readBoolean();
+ if ($exist) {
+ $binaryType->read($payload);
+ } else {
+ $binaryType = null;
+ }
+ });
+ return $binaryType;
+ }
+
+ private function putBinaryType(BinaryType $binaryType): void
+ {
+ if (!$binaryType->isValid()) {
+ BinaryUtils::serializationError(true, sprintf('type "%d" can not be registered', $binaryType->getId()));
+ }
+ $this->communicator->send(
+ ClientOperation::PUT_BINARY_TYPE,
+ function (MessageBuffer $payload) use ($binaryType)
+ {
+ $binaryType->write($payload);
+ });
+ }
+
+ private function getStorageType(int $typeId): ?BinaryType
+ {
+ return array_key_exists($typeId, $this->types) ? $this->types[$typeId] : null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryUtils.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryUtils.php b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryUtils.php
new file mode 100644
index 0000000..ad0bf56
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/BinaryUtils.php
@@ -0,0 +1,438 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Binary;
+
+use Ds\Map;
+use Ds\Set;
+use Brick\Math\BigDecimal;
+use Brick\Math\BigInteger;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Type\MapObjectType;
+use Apache\Ignite\Type\CollectionObjectType;
+use Apache\Ignite\Type\ComplexObjectType;
+use Apache\Ignite\Type\ObjectArrayType;
+use Apache\Ignite\Data\Date;
+use Apache\Ignite\Data\Time;
+use Apache\Ignite\Data\Timestamp;
+use Apache\Ignite\Data\EnumItem;
+use Apache\Ignite\Data\BinaryObject;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+
+class BinaryUtils
+{
+ const FLOAT_EPSILON = 0.00001;
+ public static $is32BitInt = PHP_INT_MAX === TypeInfo::MAX_INT_VALUE;
+
+ public static function getSize(int $typeCode): int
+ {
+ return TypeInfo::getTypeInfo($typeCode)->getSize();
+ }
+
+ public static function checkCompatibility($value, $type): void
+ {
+ if (!$type) {
+ return;
+ }
+ $typeCode = BinaryUtils::getTypeCode($type);
+ if ($value === null) {
+ if (!TypeInfo::getTypeInfo($typeCode)->isNullable()) {
+ BinaryUtils::typeCastError(ObjectType::NULL, $typeCode);
+ }
+ return;
+ } elseif (BinaryUtils::isStandardType($typeCode)) {
+ BinaryUtils::checkStandardTypeCompatibility($value, $typeCode, $type);
+ return;
+ }
+ $valueTypeCode = BinaryUtils::getTypeCode(BinaryUtils::calcObjectType($value));
+ if ($typeCode !== $valueTypeCode) {
+ BinaryUtils::typeCastError($valueTypeCode, $typeCode);
+ }
+ }
+
+ public static function isStandardType($typeCode): bool
+ {
+ return $typeCode !== ObjectType::BINARY_OBJECT &&
+ $typeCode !== ObjectType::COMPLEX_OBJECT;
+ }
+
+ public static function checkStandardTypeCompatibility($value, $typeCode, $type = null, $signed = true)
+ {
+ $valueType = BinaryUtils::getPhpTypeName($value);
+ switch ($typeCode) {
+ case ObjectType::BYTE:
+ case ObjectType::SHORT:
+ case ObjectType::INTEGER:
+ if (!is_integer($value)) {
+ BinaryUtils::valueCastError($value, $typeCode);
+ }
+ $typeInfo = TypeInfo::getTypeInfo($typeCode);
+ $min = $typeInfo->getMinValue();
+ $max = $typeInfo->getMaxValue();
+ if ($signed && ($min && $value < $min || $max && $value > $max) ||
+ !$signed && ($value < 0 || $value > $max - $min)) {
+ BinaryUtils::valueCastError($value, $typeCode);
+ }
+ return;
+ case ObjectType::LONG:
+ case ObjectType::FLOAT:
+ case ObjectType::DOUBLE:
+ if (!is_integer($value) && !is_float($value)) {
+ BinaryUtils::valueCastError($value, $typeCode);
+ }
+ return;
+ case ObjectType::CHAR:
+ if (!is_string($value) || mb_strlen($value) !== 1) {
+ BinaryUtils::valueCastError($value, $typeCode);
+ }
+ return;
+ case ObjectType::BOOLEAN:
+ if (!is_bool($value)) {
+ BinaryUtils::valueCastError($value, $typeCode);
+ }
+ return;
+ case ObjectType::STRING:
+ if (!is_string($value)) {
+ BinaryUtils::valueCastError($value, $typeCode);
+ }
+ return;
+ case ObjectType::UUID:
+ if (!BinaryUtils::isIndexedArray($value) ||
+ count($value) !== BinaryUtils::getSize(ObjectType::UUID)) {
+ BinaryUtils::valueCastError($value, $typeCode);
+ }
+ foreach ($value as $element) {
+ BinaryUtils::checkStandardTypeCompatibility($element, ObjectType::BYTE, null, false);
+ }
+ return;
+ case ObjectType::DATE:
+ if (!($value instanceof Date)) {
+ BinaryUtils::valueCastError($value, $typeCode);
+ }
+ return;
+ case ObjectType::ENUM:
+ if (!($value instanceof EnumItem)) {
+ BinaryUtils::valueCastError($value, $typeCode);
+ }
+ return;
+ case ObjectType::DECIMAL:
+ if (!($value instanceof BigDecimal)) {
+ BinaryUtils::valueCastError($value, $typeCode);
+ }
+ return;
+ case ObjectType::TIMESTAMP:
+ if (!($value instanceof Timestamp)) {
+ BinaryUtils::valueCastError($value, $typeCode);
+ }
+ return;
+ case ObjectType::TIME:
+ if (!($value instanceof Time)) {
+ BinaryUtils::valueCastError($value, $typeCode);
+ }
+ return;
+ case ObjectType::BYTE_ARRAY:
+ case ObjectType::SHORT_ARRAY:
+ case ObjectType::INTEGER_ARRAY:
+ case ObjectType::LONG_ARRAY:
+ case ObjectType::FLOAT_ARRAY:
+ case ObjectType::DOUBLE_ARRAY:
+ case ObjectType::CHAR_ARRAY:
+ case ObjectType::BOOLEAN_ARRAY:
+ case ObjectType::STRING_ARRAY:
+ case ObjectType::UUID_ARRAY:
+ case ObjectType::DATE_ARRAY:
+ case ObjectType::OBJECT_ARRAY:
+ case ObjectType::ENUM_ARRAY:
+ case ObjectType::DECIMAL_ARRAY:
+ case ObjectType::TIMESTAMP_ARRAY:
+ case ObjectType::TIME_ARRAY:
+ if (!BinaryUtils::isIndexedArray($value)) {
+ BinaryUtils::typeCastError($valueType, $typeCode);
+ }
+ return;
+ case ObjectType::MAP:
+ if (!($value instanceof Map) && !is_array($value)) {
+ BinaryUtils::typeCastError($valueType, $typeCode);
+ }
+ return;
+ case ObjectType::COLLECTION:
+ $isSet = $type && CollectionObjectType::isSet($type->getSubType());
+ if (!($isSet && $value instanceof Set || BinaryUtils::isIndexedArray($value))) {
+ BinaryUtils::typeCastError($valueType, $isSet ? 'set' : $typeCode);
+ }
+ return;
+ case ObjectType::NULL:
+ if ($value !== null) {
+ BinaryUtils::typeCastError('not null', $typeCode);
+ }
+ return;
+ default:
+ $valueTypeCode = BinaryUtils::getTypeCode(BinaryUtils::calcObjectType($value));
+ if ($valueTypeCode === ObjectType::BINARY_OBJECT) {
+ BinaryUtils::typeCastError($valueTypeCode, $typeCode);
+ }
+ return;
+ }
+ }
+
+ public static function checkTypesCompatibility($expectedType, int $actualTypeCode): void
+ {
+ if ($expectedType === null) {
+ return;
+ }
+ $expectedTypeCode = BinaryUtils::getTypeCode($expectedType);
+ if ($actualTypeCode === ObjectType::NULL) {
+ return;
+ } elseif ($expectedTypeCode === ObjectType::BINARY_OBJECT ||
+ $actualTypeCode === ObjectType::BINARY_OBJECT &&
+ $expectedTypeCode === ObjectType::COMPLEX_OBJECT) {
+ return;
+ } elseif ($actualTypeCode !== $expectedTypeCode) {
+ BinaryUtils::typeCastError($actualTypeCode, $expectedTypeCode);
+ }
+ }
+
+ public static function calcObjectType($object)
+ {
+ if (is_integer($object)) {
+ return ObjectType::INTEGER;
+ } elseif (is_float($object)) {
+ return ObjectType::DOUBLE;
+ } elseif (is_string($object)) {
+ return ObjectType::STRING;
+ } elseif (is_bool($object)) {
+ return ObjectType::BOOLEAN;
+ } elseif (is_array($object)) {
+ if (count($object) > 0) {
+ if (BinaryUtils::isIndexedArray($object)) {
+ if ($object[0] !== null) {
+ // indexed array
+ return BinaryUtils::getArrayType(BinaryUtils::calcObjectType($object[0]));
+ }
+ } else {
+ // associative array
+ return new MapObjectType();
+ }
+ } else {
+ BinaryUtils::noDefaultMapping("empty array");
+ }
+ } elseif ($object instanceof Time) {
+ return ObjectType::TIME;
+ } elseif ($object instanceof Timestamp) {
+ return ObjectType::TIMESTAMP;
+ } elseif ($object instanceof Date) {
+ return ObjectType::DATE;
+ } elseif ($object instanceof EnumItem) {
+ return ObjectType::ENUM;
+ } elseif ($object instanceof BigDecimal) {
+ return ObjectType::DECIMAL;
+ } elseif ($object instanceof Set) {
+ return new CollectionObjectType(CollectionObjectType::HASH_SET);
+ } elseif ($object instanceof Map) {
+ return new MapObjectType();
+ } elseif ($object instanceof BinaryObject) {
+ return ObjectType::BINARY_OBJECT;
+ } elseif (is_object($object)) {
+ return new ComplexObjectType();
+ }
+ BinaryUtils::noDefaultMapping(BinaryUtils::getPhpTypeName($object));
+ return null;
+ }
+
+ public static function getArrayType($elementType)
+ {
+ switch (BinaryUtils::getTypeCode($elementType)) {
+ case ObjectType::BYTE:
+ return ObjectType::BYTE_ARRAY;
+ case ObjectType::SHORT:
+ return ObjectType::SHORT_ARRAY;
+ case ObjectType::INTEGER:
+ return ObjectType::INTEGER_ARRAY;
+ case ObjectType::LONG:
+ return ObjectType::LONG_ARRAY;
+ case ObjectType::FLOAT:
+ return ObjectType::FLOAT_ARRAY;
+ case ObjectType::DOUBLE:
+ return ObjectType::DOUBLE_ARRAY;
+ case ObjectType::CHAR:
+ return ObjectType::CHAR_ARRAY;
+ case ObjectType::BOOLEAN:
+ return ObjectType::BOOLEAN_ARRAY;
+ case ObjectType::STRING:
+ return ObjectType::STRING_ARRAY;
+ case ObjectType::UUID:
+ return ObjectType::UUID_ARRAY;
+ case ObjectType::DATE:
+ return ObjectType::DATE_ARRAY;
+ case ObjectType::ENUM:
+ return ObjectType::ENUM_ARRAY;
+ case ObjectType::DECIMAL:
+ return ObjectType::DECIMAL_ARRAY;
+ case ObjectType::TIMESTAMP:
+ return ObjectType::TIMESTAMP_ARRAY;
+ case ObjectType::TIME:
+ return ObjectType::TIME_ARRAY;
+ case ObjectType::BINARY_OBJECT:
+ return new ObjectArrayType();
+ default:
+ return new ObjectArrayType($elementType);
+ }
+ }
+
+ public static function getArrayElementType($arrayType)
+ {
+ if ($arrayType instanceof ObjectArrayType) {
+ return $arrayType->getElementType();
+ } elseif ($arrayType === ObjectType::OBJECT_ARRAY) {
+ return null;
+ }
+ $info = TypeInfo::getTypeInfo($arrayType);
+ if (!$info || !$info->getElementTypeCode()) {
+ BinaryUtils::internalError();
+ }
+ return $info->getElementTypeCode();
+ }
+
+ public static function getTypeCode($objectType): int
+ {
+ return $objectType instanceof ObjectType ? $objectType->getTypeCode() : $objectType;
+ }
+
+ public static function getTypeName($objectType): string
+ {
+ if (is_string($objectType)) {
+ return $objectType;
+ }
+ $typeCode = BinaryUtils::getTypeCode($objectType);
+ $info = TypeInfo::getTypeInfo($typeCode);
+ return $info ? $info->getName() : 'type code ' . $typeCode;
+ }
+
+ public static function getPhpTypeName($object): string
+ {
+ if (is_array($object) && !BinaryUtils::isIndexedArray($object)) {
+ return 'associative array';
+ }
+ return gettype($object);
+ }
+
+ public static function checkObjectType($type, string $argName): void
+ {
+ if ($type === null || $type instanceof ObjectType) {
+ return;
+ }
+ ArgumentChecker::hasValueFrom($type, $argName, false, TypeInfo::getPrimitiveTypes());
+ }
+
+ public static function floatEquals(float $val1, float $val2): bool
+ {
+ return abs($val1 - $val2) < BinaryUtils::FLOAT_EPSILON;
+ }
+
+ public static function getLongHex(BigInteger $value, bool $isNegative): string
+ {
+ $size = TypeInfo::getTypeInfo(ObjectType::LONG)->getSize();
+ if ($isNegative) {
+ $value = BigInteger::parse(str_pad('1', $size * 2 + 1, '0'), 16)->minus($value);
+ }
+ return str_pad($value->toBase(16), $size * 2, '0', STR_PAD_LEFT);
+ }
+
+ public static function hashCode(?string $str): int
+ {
+ $hash = 0;
+ $length = strlen($str);
+ if ($str && $length > 0) {
+ for ($i = 0; $i < $length; $i++) {
+ $hash = (($hash << 5) - $hash) + ord($str[$i]);
+ $hash &= 0xFFFFFFFF; // Convert to 32bit integer
+ }
+ }
+ return BinaryUtils::intVal32($hash);
+ }
+
+ public static function hashCodeLowerCase(?string $str): int
+ {
+ return BinaryUtils::hashCode($str ? strtolower($str) : $str);
+ }
+
+ public static function contentHashCode(MessageBuffer $buffer, int $startPos, int $endPos): int
+ {
+ $hash = 1;
+ $length = $endPos - $startPos + 1;
+ $content = $buffer->getSlice($startPos, $length);
+ for ($i = 0; $i < $length; $i++) {
+ $hash = 31 * $hash + ord($content[$i]);
+ $hash &= 0xFFFFFFFF; // Convert to 32bit integer
+ }
+ return BinaryUtils::intVal32($hash);
+ }
+
+ public static function intVal32(int $value): int
+ {
+ if (!BinaryUtils::$is32BitInt) {
+ $value = ($value & 0xFFFFFFFF);
+ if ($value & 0x80000000) {
+ $value = -((~$value & 0xFFFFFFFF) + 1);
+ }
+ }
+ return $value;
+ }
+
+ public static function internalError(string $message = null): void
+ {
+ throw new ClientException($message ? $message : 'Internal library error');
+ }
+
+ public static function unsupportedType($type): void
+ {
+ throw new ClientException(sprintf('Type %s is not supported', BinaryUtils::getTypeName($type)));
+ }
+
+ public static function noDefaultMapping($type): void
+ {
+ throw new ClientException(sprintf('%s has no default type mapping', BinaryUtils::getTypeName($type)));
+ }
+
+ public static function serializationError(bool $serialize, string $message = null): void
+ {
+ $msg = $serialize ? 'Complex object can not be serialized' : 'Complex object can not be deserialized';
+ if ($message) {
+ $msg = $msg . ': ' . $message;
+ }
+ throw new ClientException($msg);
+ }
+
+ public static function typeCastError($fromType, $toType): void
+ {
+ throw new ClientException(sprintf('Type "%s" can not be cast to %s',
+ BinaryUtils::getTypeName($fromType), BinaryUtils::getTypeName($toType)));
+ }
+
+ public static function valueCastError($value, $toType): void
+ {
+ throw new ClientException(sprintf('Value "%s" can not be cast to %s',
+ print_r($value, true), BinaryUtils::getTypeName($toType)));
+ }
+
+ private static function isIndexedArray(array $object): bool
+ {
+ return $object === array_values($object);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Binary/ClientOperation.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Binary/ClientOperation.php b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/ClientOperation.php
new file mode 100644
index 0000000..bfc6c17
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/ClientOperation.php
@@ -0,0 +1,64 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Binary;
+
+class ClientOperation
+{
+ // Key-Value Queries
+ const CACHE_GET = 1000;
+ const CACHE_PUT = 1001;
+ const CACHE_PUT_IF_ABSENT = 1002;
+ const CACHE_GET_ALL = 1003;
+ const CACHE_PUT_ALL = 1004;
+ const CACHE_GET_AND_PUT = 1005;
+ const CACHE_GET_AND_REPLACE = 1006;
+ const CACHE_GET_AND_REMOVE = 1007;
+ const CACHE_GET_AND_PUT_IF_ABSENT = 1008;
+ const CACHE_REPLACE = 1009;
+ const CACHE_REPLACE_IF_EQUALS = 1010;
+ const CACHE_CONTAINS_KEY = 1011;
+ const CACHE_CONTAINS_KEYS = 1012;
+ const CACHE_CLEAR = 1013;
+ const CACHE_CLEAR_KEY = 1014;
+ const CACHE_CLEAR_KEYS = 1015;
+ const CACHE_REMOVE_KEY = 1016;
+ const CACHE_REMOVE_IF_EQUALS = 1017;
+ const CACHE_REMOVE_KEYS = 1018;
+ const CACHE_REMOVE_ALL = 1019;
+ const CACHE_GET_SIZE = 1020;
+ // Cache Configuration
+ const CACHE_GET_NAMES = 1050;
+ const CACHE_CREATE_WITH_NAME = 1051;
+ const CACHE_GET_OR_CREATE_WITH_NAME = 1052;
+ const CACHE_CREATE_WITH_CONFIGURATION = 1053;
+ const CACHE_GET_OR_CREATE_WITH_CONFIGURATION = 1054;
+ const CACHE_GET_CONFIGURATION = 1055;
+ const CACHE_DESTROY = 1056;
+ // SQL and Scan Queries
+ const QUERY_SCAN = 2000;
+ const QUERY_SCAN_CURSOR_GET_PAGE = 2001;
+ const QUERY_SQL = 2002;
+ const QUERY_SQL_CURSOR_GET_PAGE = 2003;
+ const QUERY_SQL_FIELDS = 2004;
+ const QUERY_SQL_FIELDS_CURSOR_GET_PAGE = 2005;
+ const RESOURCE_CLOSE = 0;
+ // Binary Types
+ const GET_BINARY_TYPE = 3002;
+ const PUT_BINARY_TYPE = 3003;
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Binary/MessageBuffer.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Binary/MessageBuffer.php b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/MessageBuffer.php
new file mode 100644
index 0000000..920df65
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/MessageBuffer.php
@@ -0,0 +1,307 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Binary;
+
+use Apache\Ignite\Type\ObjectType;
+use Brick\Math\BigInteger;
+
+class MessageBuffer
+{
+ const BYTE_ZERO = 0;
+ const BYTE_ONE = 1;
+ const BUFFER_CAPACITY_DEFAULT = 256;
+
+ const PROTOCOL_STRING_ENCODING = 'UTF-8';
+
+ private $buffer;
+ private $position;
+ private $length;
+
+ private static $isLittleEndian;
+ private static $defaultEncoding;
+
+ public static function init(): void
+ {
+ MessageBuffer::$isLittleEndian = pack('L', 1) === pack('V', 1);
+ MessageBuffer::$defaultEncoding = ini_get('default_charset');
+ }
+
+ public function __construct(int $capacity = MessageBuffer::BUFFER_CAPACITY_DEFAULT)
+ {
+ $this->buffer = '';
+ $this->position = 0;
+ $this->length = 0;
+ $this->ensureCapacity($capacity);
+ }
+
+ public function getLength(): int
+ {
+ return $this->length;
+ }
+
+ public function getBuffer(): string
+ {
+ return $this->getSlice(0, $this->getLength());
+ }
+
+ public function getSlice(int $startPos, int $length): string
+ {
+ return substr($this->buffer, $startPos, $length);
+ }
+
+ public function getPosition(): int
+ {
+ return $this->position;
+ }
+
+ public function setPosition(int $position): void
+ {
+ $this->ensureCapacity($position);
+ $this->position = $position;
+ }
+
+ public function append(string &$buffer): void
+ {
+ $this->buffer .= $buffer;
+ $this->length += strlen($buffer);
+ }
+
+ public function writeByte(int $value, $signed = true): void
+ {
+ $this->writeNumber($value, ObjectType::BYTE, $signed);
+ }
+
+ public function writeShort(int $value): void
+ {
+ $this->writeNumber($value, ObjectType::SHORT);
+ }
+
+ public function writeInteger(int $value): void
+ {
+ $this->writeNumber($value, ObjectType::INTEGER);
+ }
+
+ public function writeLong(float $value): void
+ {
+ $this->writeNumber($value, ObjectType::LONG);
+ }
+
+ public function writeFloat(float $value): void
+ {
+ $this->writeNumber($value, ObjectType::FLOAT);
+ }
+
+ public function writeDouble(float $value): void
+ {
+ $this->writeNumber($value, ObjectType::DOUBLE);
+ }
+
+ public function writeNumber($value, int $type, bool $signed = true): void
+ {
+ $size = TypeInfo::getTypeInfo($type)->getSize();
+ if ($type === ObjectType::LONG && BinaryUtils::$is32BitInt) {
+ // pack longs doesn't work on 32-bit versions of PHP
+ $strValue = strrev(hex2bin(BinaryUtils::getLongHex(BigInteger::of(abs($value)), $value < 0)));
+ } else {
+ $format = $this->getNumberFormat($type, $signed);
+ $strValue = pack($format, $value);
+ $this->convertEndianness($strValue, $type);
+ }
+ if (strlen($strValue) !== $size) {
+ BinaryUtils::unsupportedType(BinaryUtils::getTypeName($type));
+ }
+ $this->writeStr($strValue);
+ }
+
+ public function writeBoolean(bool $value): void
+ {
+ $this->writeByte($value ? MessageBuffer::BYTE_ONE : MessageBuffer::BYTE_ZERO);
+ }
+
+ public function writeChar(string $value): void
+ {
+ $this->writeShort(mb_ord($value));
+ }
+
+ public function writeString(string $value, bool $encode = true): void
+ {
+ if ($encode) {
+ $value = mb_convert_encoding($value, self::PROTOCOL_STRING_ENCODING, self::$defaultEncoding);
+ }
+ $length = strlen($value);
+ $this->writeInteger($length);
+ if ($length > 0) {
+ $this->writeStr($value);
+ }
+ }
+
+ public function writeBuffer(MessageBuffer $buffer, int $startPos, int $length): void
+ {
+ $this->writeStr($buffer->buffer, $startPos, $length);
+ }
+
+ public function readByte(bool $signed = true): int
+ {
+ return $this->readNumber(ObjectType::BYTE, $signed);
+ }
+
+ public function readShort(): int
+ {
+ return $this->readNumber(ObjectType::SHORT);
+ }
+
+ public function readInteger(): int
+ {
+ return $this->readNumber(ObjectType::INTEGER);
+ }
+
+ public function readLong(): float
+ {
+ return $this->readNumber(ObjectType::LONG);
+ }
+
+ public function readFloat(): float
+ {
+ return $this->readNumber(ObjectType::FLOAT);
+ }
+
+ public function readDouble(): float
+ {
+ return $this->readNumber(ObjectType::DOUBLE);
+ }
+
+ public function readNumber(int $type, bool $signed = true)
+ {
+ $size = BinaryUtils::getSize($type);
+ $this->ensureSize($size);
+ $strValue = substr($this->buffer, $this->position, $size);
+ if ($type === ObjectType::LONG && BinaryUtils::$is32BitInt) {
+ // unpack longs doesn't work on 32-bit versions of PHP
+ $binValue = strrev($strValue);
+ $isNegative = ord($binValue[0]) & 0x80;
+ $hexValue = bin2hex($binValue);
+ $bigIntValue = BigInteger::parse($hexValue, 16);
+ if ($isNegative) {
+ $bigIntValue = BigInteger::parse(str_pad('1', $size * 2 + 1, '0'), 16)->minus($bigIntValue);
+ }
+ $value = $bigIntValue->toFloat();
+ if ($isNegative) {
+ $value = -$value;
+ }
+ } else {
+ $this->convertEndianness($strValue, $type);
+ $value = unpack($this->getNumberFormat($type, $signed), $strValue);
+ $value = $value[1];
+ }
+ $this->position += $size;
+ return $value;
+ }
+
+ public function readBoolean(): bool
+ {
+ return $this->readByte() === MessageBuffer::BYTE_ONE;
+ }
+
+ public function readChar(): string
+ {
+ return mb_chr($this->readShort());
+ }
+
+ public function readString(bool $decode = true): string
+ {
+ $bytesCount = $this->readInteger();
+ $this->ensureSize($bytesCount);
+ $result = substr($this->buffer, $this->position, $bytesCount);
+ if ($decode) {
+ $result = mb_convert_encoding($result, self::$defaultEncoding, self::PROTOCOL_STRING_ENCODING);
+ }
+ $this->position += $bytesCount;
+ return $result;
+ }
+
+ private function getNumberFormat(int $type, bool $signed): string
+ {
+ switch ($type) {
+ case ObjectType::BYTE:
+ return $signed ? 'c' : 'C';
+ case ObjectType::SHORT:
+ return $signed ? 's' : 'S';
+ case ObjectType::INTEGER:
+ return $signed ? 'l' : 'L';
+ case ObjectType::LONG:
+ return $signed ? 'q' : 'Q';
+ case ObjectType::FLOAT:
+ return 'g';
+ case ObjectType::DOUBLE:
+ return 'e';
+ default:
+ BinaryUtils::internalError();
+ }
+ return null;
+ }
+
+ private function convertEndianness(string &$value, int $type): void
+ {
+ if (!MessageBuffer::$isLittleEndian &&
+ ($type === ObjectType::SHORT ||
+ $type === ObjectType::INTEGER ||
+ $type === ObjectType::LONG)) {
+ $value = strrev($value);
+ }
+ }
+
+ private function writeStr(string &$buffer, int $startPos = 0, int $length = -1): void
+ {
+ if ($length < 0) {
+ $length = strlen($buffer);
+ }
+ $this->ensureCapacity($length);
+ for ($i = 0; $i < $length; $i++) {
+ $this->buffer[$this->position + $i] = $buffer[$startPos + $i];
+ }
+ if ($this->position + $length > $this->length) {
+ $this->length = $this->position + $length;
+ }
+ $this->position += $length;
+ }
+
+ private function ensureCapacity(int $size): void
+ {
+ if ($size <= 0) {
+ return;
+ }
+ $capacity = strlen($this->buffer);
+ $newCapacity = $capacity > 0 ? $capacity : $size;
+ while ($this->position + $size > $newCapacity) {
+ $newCapacity = $newCapacity * 2;
+ }
+ if ($capacity < $newCapacity) {
+ $this->buffer .= str_repeat('0', $newCapacity - $capacity);
+ }
+ }
+
+ private function ensureSize(int $size): void
+ {
+ if ($this->position + $size > $this->getLength()) {
+ BinaryUtils::internalError('Unexpected format of response');
+ }
+ }
+}
+
+MessageBuffer::init();
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Binary/Request.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Binary/Request.php b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/Request.php
new file mode 100644
index 0000000..2d22646
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/Request.php
@@ -0,0 +1,85 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Binary;
+
+use Apache\Ignite\Type\ObjectType;
+
+class Request
+{
+ private $id;
+ private $opCode;
+ private $payloadWriter;
+ private $payloadReader;
+ private $isHandshake;
+
+ private static $requestId = 0;
+
+ public function __construct(int $opCode, ?callable $payloadWriter, callable $payloadReader = null, bool $isHandshake = false)
+ {
+ $this->id = Request::getRequestId();
+ $this->opCode = $opCode;
+ $this->payloadWriter = $payloadWriter;
+ $this->payloadReader = $payloadReader;
+ $this->isHandshake = $isHandshake;
+ }
+
+ public function getId(): int
+ {
+ return $this->id;
+ }
+
+ public function isHandshake(): bool
+ {
+ return $this->isHandshake;
+ }
+
+ public function getMessage(): MessageBuffer
+ {
+ $message = new MessageBuffer();
+ // Skip message length
+ $messageStartPos = BinaryUtils::getSize(ObjectType::INTEGER);
+ $message->setPosition($messageStartPos);
+ if ($this->opCode >= 0) {
+ // Op code
+ $message->writeShort($this->opCode);
+ // Request id
+ $message->writeLong($this->id);
+ }
+ if ($this->payloadWriter !== null) {
+ // Payload
+ call_user_func($this->payloadWriter, $message);
+ }
+ // Message length
+ $message->setPosition(0);
+ $message->writeInteger($message->getLength() - $messageStartPos);
+ return $message;
+ }
+
+ public function getPayloadReader(): ?callable
+ {
+ return $this->payloadReader;
+ }
+
+ private static function getRequestId(): int
+ {
+ $result = Request::$requestId;
+ Request::$requestId++;
+ return $result;
+ }
+}
[3/9] ignite git commit: IGNITE-7783: PHP thin client
Posted by is...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Type/CollectionObjectType.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Type/CollectionObjectType.php b/modules/platforms/php/src/Apache/Ignite/Type/CollectionObjectType.php
new file mode 100644
index 0000000..b9591cb
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Type/CollectionObjectType.php
@@ -0,0 +1,142 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Type;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+
+/**
+ * Class representing a collection type of Ignite object.
+ *
+ * It is described by ObjectType::COLLECTION and one of @ref CollectionSubType.
+ */
+class CollectionObjectType extends ObjectType
+{
+ /** @name CollectionSubType
+ * @anchor CollectionSubType
+ * @{
+ */
+
+ /**
+ * General set type, which can not be mapped to more specific set type.
+ */
+ const USER_SET = -1;
+
+ /**
+ * General collection type, which can not be mapped to any specific collection type.
+ */
+ const USER_COL = 0;
+
+ /**
+ * Resizeable array type.
+ */
+ const ARRAY_LIST = 1;
+
+ /**
+ * Linked list type.
+ */
+ const LINKED_LIST = 2;
+
+ /**
+ * Basic hash set type.
+ */
+ const HASH_SET = 3;
+
+ /**
+ * Hash set type, which maintains element order.
+ */
+ const LINKED_HASH_SET = 4;
+
+ /**
+ * This is a collection that only contains a single element, but behaves as a collection.
+ */
+ const SINGLETON_LIST = 5;
+
+ /** @} */ // end of CollectionSubType
+
+ private $subType;
+ private $elementType;
+
+ /**
+ * Public constructor.
+ *
+ * Specifies the collection subtype and optionally specifies Ignite type of elements in the collection.
+ *
+ * If Ignite type of elements is not specified then during operations the Ignite client
+ * tries to make automatic mapping between PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * @param int $subType collection subtype, one of @ref CollectionSubType constants.
+ * @param int|ObjectType|null $elementType Ignite type of elements in the collection:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (or not specified) that means the type is not specified
+ *
+ * @throws ClientException if error.
+ */
+ public function __construct(int $subType, $elementType = null)
+ {
+ parent::__construct(ObjectType::COLLECTION);
+ ArgumentChecker::hasValueFrom(
+ $subType, 'subType', false,
+ [
+ CollectionObjectType::USER_SET,
+ CollectionObjectType::USER_COL,
+ CollectionObjectType::ARRAY_LIST,
+ CollectionObjectType::LINKED_LIST,
+ CollectionObjectType::HASH_SET,
+ CollectionObjectType::LINKED_HASH_SET,
+ CollectionObjectType::SINGLETON_LIST
+ ]);
+ BinaryUtils::checkObjectType($elementType, 'elementType');
+ $this->subType = $subType;
+ $this->elementType = $elementType;
+ }
+
+ /**
+ * Returns collection subtype, one of @ref CollectionSubType constants.
+ *
+ * @return int collection subtype, one of @ref CollectionSubType constants.
+ */
+ public function getSubType(): int
+ {
+ return $this->subType;
+ }
+
+ /**
+ * Returns Ignite type of elements in the collection.
+ *
+ * @return int|ObjectType|null type of elements in the collection:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null that means the type is not specified
+ */
+ public function getElementType()
+ {
+ return $this->elementType;
+ }
+
+ public static function isSet($subType): bool
+ {
+ return $subType === CollectionObjectType::USER_SET ||
+ $subType === CollectionObjectType::HASH_SET ||
+ $subType === CollectionObjectType::LINKED_HASH_SET;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Type/ComplexObjectType.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Type/ComplexObjectType.php b/modules/platforms/php/src/Apache/Ignite/Type/ComplexObjectType.php
new file mode 100644
index 0000000..b62272e
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Type/ComplexObjectType.php
@@ -0,0 +1,165 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Type;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+
+/**
+ * Class representing a complex type of Ignite object.
+ *
+ * It corresponds to the ObjectType::COMPLEX_OBJECT Ignite type code.
+ *
+ * This class may be needed to help Ignite client to:
+ * - deserialize an Ignite complex object to a PHP object when reading data,
+ * - serialize a PHP object to an Ignite complex object when writing data.
+ *
+ * Note: only public properties of PHP objects can be serialized/deserialized.
+ */
+class ComplexObjectType extends ObjectType
+{
+ private $phpClassName;
+ private $typeName;
+ private $fieldTypes;
+
+ /**
+ * Public constructor.
+ *
+ * Creates a default representation of Ignite complex object type.
+ * setPhpClassName(), setIgniteTypeName(), setFieldType() methods may be used
+ * to change the default representation.
+ */
+ public function __construct()
+ {
+ parent::__construct(ObjectType::COMPLEX_OBJECT);
+ $this->phpClassName = null;
+ $this->typeName = null;
+ $this->fieldTypes = [];
+ }
+
+ /**
+ * Sets the name of the PHP class.
+ *
+ * Affects data reading operations only.
+ *
+ * The specified name will be used as PHP class name to instantiate a PHP object
+ * the received Ignite complex object is deserialized to.
+ *
+ * By default (if the name is not specified), the Ignite complex type name of the received complex object
+ * is used as PHP class name to instantiate a PHP object during deserialization.
+ *
+ * The PHP Class must have a constructor without parameters or with optional parameters only.
+ *
+ * @param string|null $phpClassName name of the PHP class or null (the name is not specified).
+ *
+ * @return ComplexObjectType the same instance of the ComplexObjectType.
+ */
+ public function setPhpClassName(?string $phpClassName): ComplexObjectType
+ {
+ $this->phpClassName = $phpClassName;
+ return $this;
+ }
+
+ /**
+ * Gets the name of the PHP class.
+ *
+ * @return string|null name of the PHP class or null (the name is not specified).
+ */
+ public function getPhpClassName(): ?string
+ {
+ return $this->phpClassName;
+ }
+
+ /**
+ * Sets the name of the Ignite complex type.
+ *
+ * Affects data writing operations only.
+ *
+ * The specified name will be used as the Ignite complex type name during the complex object's writing operations.
+ *
+ * By default (if the name is not specified), the Ignite complex type name of the serialized complex object
+ * is taken from the name of the PHP class which instance is provided in a data writing operation.
+ *
+ * @param string|null $typeName name of the Ignite complex type or null (the name is not specified).
+ *
+ * @return ComplexObjectType the same instance of the ComplexObjectType.
+ */
+ public function setIgniteTypeName(?string $typeName): ComplexObjectType
+ {
+ $this->typeName = $typeName;
+ return $this;
+ }
+
+ /**
+ * Gets the name of the Ignite complex type.
+ *
+ * @return string|null name of the Ignite complex type or null (the name is not specified).
+ */
+ public function getIgniteTypeName(): ?string
+ {
+ return $this->typeName;
+ }
+
+ /**
+ * Specifies Ignite type of the indicated field in the complex type.
+ *
+ * Affects data writing operations only.
+ *
+ * During data serialization Ignite client will assume that the indicated field
+ * has the Ignite type specified by this method.
+ *
+ * By default (if the type of the field is not specified),
+ * Ignite client tries to make automatic mapping between PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * @param string $fieldName name of the field.
+ * @param int|ObjectType|null $fieldType Ignite type of the field:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (or not specified) that means the type is not specified
+ *
+ * @return ComplexObjectType the same instance of the ComplexObjectType.
+ *
+ * @throws ClientException if error.
+ */
+ public function setFieldType(string $fieldName, $fieldType): ComplexObjectType
+ {
+ BinaryUtils::checkObjectType($fieldType, 'fieldType');
+ $this->fieldTypes[$fieldName] = $fieldType;
+ return $this;
+ }
+
+ /**
+ * Gets Ignite type of the indicated field in the complex type.
+ *
+ * @param string $fieldName name of the field.
+ *
+ * @return int|ObjectType|null Ignite type of the field:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null that means the type is not specified
+ */
+ public function getFieldType(string $fieldName)
+ {
+ if (array_key_exists($fieldName, $this->fieldTypes)) {
+ return $this->fieldTypes[$fieldName];
+ }
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Type/MapObjectType.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Type/MapObjectType.php b/modules/platforms/php/src/Apache/Ignite/Type/MapObjectType.php
new file mode 100644
index 0000000..043ae6a
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Type/MapObjectType.php
@@ -0,0 +1,123 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Type;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+
+/**
+ * Class representing a map type of Ignite object.
+ *
+ * It is described by ObjectType::MAP and one of @ref MapSubType.
+ */
+class MapObjectType extends ObjectType
+{
+ /** @name MapSubType
+ * @anchor MapSubType
+ * @{
+ */
+
+ /**
+ * Basic hash map.
+ */
+ const HASH_MAP = 1;
+
+ /**
+ * Hash map, which maintains element order.
+ */
+ const LINKED_HASH_MAP = 2;
+
+ /** @} */ // end of MapSubType
+
+ private $subType;
+ private $keyType;
+ private $valueType;
+
+ /**
+ * Public constructor.
+ *
+ * Optionally specifies the map subtype and Ignite types of keys and values in the map.
+ *
+ * If the map subtype is not specified, MapObjectType::HASH_MAP is assumed.
+ *
+ * If Ignite type is not specified for the key and/or value then during operations the Ignite client
+ * tries to make automatic mapping between PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * @param int $subType map subtype, one of @ref MapSubType constants.
+ * @param int|ObjectType|null $keyType Ignite type of the keys in the map:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (or not specified) that means the type is not specified
+ * @param int|ObjectType|null $valueType Ignite type of the values in the map:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (or not specified) that means the type is not specified
+ *
+ * @throws ClientException if error.
+ */
+ public function __construct(int $subType = MapObjectType::HASH_MAP, $keyType = null, $valueType = null)
+ {
+ parent::__construct(ObjectType::MAP);
+ ArgumentChecker::hasValueFrom(
+ $subType, 'subType', false, [MapObjectType::HASH_MAP, MapObjectType::LINKED_HASH_MAP]);
+ BinaryUtils::checkObjectType($keyType, 'keyType');
+ BinaryUtils::checkObjectType($valueType, 'valueType');
+ $this->subType = $subType;
+ $this->keyType = $keyType;
+ $this->valueType = $valueType;
+ }
+
+ /**
+ * Returns the map subtype, one of @ref MapSubType constants.
+ *
+ * @return int map subtype, one of @ref MapSubType constants.
+ */
+ public function getSubType(): int
+ {
+ return $this->subType;
+ }
+
+ /**
+ * Returns Ignite type of the keys in the map.
+ *
+ * @return int|ObjectType|null type of the keys in the map:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null that means the type is not specified
+ */
+ public function getKeyType()
+ {
+ return $this->keyType;
+ }
+
+ /**
+ * Returns Ignite type of the values in the map.
+ *
+ * @return int|ObjectType|null type of the values in the map:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null that means the type is not specified
+ */
+ public function getValueType()
+ {
+ return $this->valueType;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Type/ObjectArrayType.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Type/ObjectArrayType.php b/modules/platforms/php/src/Apache/Ignite/Type/ObjectArrayType.php
new file mode 100644
index 0000000..89c8eca
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Type/ObjectArrayType.php
@@ -0,0 +1,68 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Type;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+
+/**
+ * Class representing an array type of Ignite objects.
+ *
+ * It is described by ObjectType::OBJECT_ARRAY.
+ */
+class ObjectArrayType extends ObjectType
+{
+ private $elementType;
+
+ /**
+ * Public constructor.
+ *
+ * Optionally specifies Ignite type of elements in the array.
+ *
+ * If Ignite type of elements is not specified then during operations the Ignite client
+ * tries to make automatic mapping between PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * @param int|ObjectType|null $elementType Ignite type of the array element:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (or not specified) that means the type is not specified
+ *
+ * @throws ClientException if error.
+ */
+ public function __construct($elementType = null)
+ {
+ parent::__construct(ObjectType::OBJECT_ARRAY);
+ BinaryUtils::checkObjectType($elementType, 'elementType');
+ $this->elementType = $elementType;
+ }
+
+ /**
+ * Returns Ignite type of the array element.
+ *
+ * @return int|ObjectType|null Ignite type of the array element:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null that means the type is not specified
+ */
+ public function getElementType()
+ {
+ return $this->elementType;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Type/ObjectType.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Type/ObjectType.php b/modules/platforms/php/src/Apache/Ignite/Type/ObjectType.php
new file mode 100644
index 0000000..c91d120
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Type/ObjectType.php
@@ -0,0 +1,442 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Type;
+
+/**
+ * Base class representing a type of Ignite object.
+ *
+ * The class is abstract and has no public constructor. Only subclasses may be instantiated.
+ *
+ * There are two groups of Ignite object types:
+ *
+ * - Primitive (simple) types. To fully describe such a type:
+ * it is enough to specify Ignite type code @ref PrimitiveTypeCodes only.
+ *
+ * - Non-primitive (composite) types. To fully describe such a type:
+ * Ignite type code @ref CompositeTypeCodes with additional information
+ * (eg. a kind of map or a kind of collection) should be specified.
+ *
+ * This class helps the Ignite client to make a mapping between PHP types
+ * and types used by Ignite according to the following mapping tables:
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * COMMENTS TO ALL TABLES
+ * ----------------
+ *
+ * PHP type
+ * ----------------
+ * It is a PHP primitive or a PHP object: http://php.net/manual/en/language.types.intro.php
+ *
+ * Associative and indexed PHP arrays: http://php.net/manual/en/language.types.array.php
+ *
+ * Additional types:
+ * - Ds\\Set, Ds\\Map - PHP Data Structures extension classes: http://php.net/manual/en/book.ds.php
+ * - Brick\\Math\\BigDecimal - PHP class from the extension library
+ * to work with arbitrary precision numbers: https://github.com/brick/math
+ * - Date, Time, Timestamp, EnumItem, BinaryObject - PHP classes introduced by the Ignite client.
+ *
+ * Ignite type code
+ * ----------------
+ * It is a type code of Ignite primitive type (@ref PrimitiveTypeCodes)
+ * or Ignite composite type (@ref CompositeTypeCodes).
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * MAPPING FROM IGNITE TYPE CODE TO PHP TYPE WHEN READING DATA
+ * ----------------
+ *
+ * | Ignite type code | PHP type |
+ * | ---------------------------- | ----------------------------------------------|
+ * | BYTE | integer |
+ * | SHORT | integer |
+ * | INTEGER | integer |
+ * | LONG | float |
+ * | FLOAT | float |
+ * | DOUBLE | float |
+ * | DECIMAL | Brick\\Math\\BigDecimal |
+ * | BOOLEAN | boolean |
+ * | STRING | string |
+ * | CHAR | string (one character) |
+ * | UUID | indexed array of integers (16 items) |
+ * | DATE | Date |
+ * | TIME | Time |
+ * | TIMESTAMP | Timestamp |
+ * | ENUM | EnumItem |
+ * | COMPLEX_OBJECT | BinaryObject or PHP object* |
+ * | BYTE_ARRAY | indexed array of integer |
+ * | SHORT_ARRAY | indexed array of integer |
+ * | INTEGER_ARRAY | indexed array of integer |
+ * | LONG_ARRAY | indexed array of float |
+ * | FLOAT_ARRAY | indexed array of float |
+ * | DOUBLE_ARRAY | indexed array of float |
+ * | DECIMAL_ARRAY | indexed array of Brick\\Math\\BigDecimal |
+ * | BOOLEAN_ARRAY | indexed array of boolean |
+ * | STRING_ARRAY | indexed array of string |
+ * | CHAR_ARRAY | indexed array of string (one character) |
+ * | UUID_ARRAY | indexed array of array of integers (16 items) |
+ * | DATE_ARRAY | indexed array of Date |
+ * | TIME_ARRAY | indexed array of Time |
+ * | TIMESTAMP_ARRAY | indexed array of Timestamp |
+ * | ENUM_ARRAY | indexed array of EnumItem |
+ * | OBJECT_ARRAY | indexed array |
+ * | COLLECTION (USER_COL) | indexed array |
+ * | COLLECTION (ARR_LIST) | indexed array |
+ * | COLLECTION (LINKED_LIST) | indexed array |
+ * | COLLECTION (SINGLETON_LIST) | indexed array |
+ * | COLLECTION (HASH_SET) | Ds\\Set |
+ * | COLLECTION (LINKED_HASH_SET) | Ds\\Set |
+ * | COLLECTION (USER_SET) | Ds\\Set |
+ * | MAP (HASH_MAP) | Ds\\Map |
+ * | MAP (LINKED_HASH_MAP) | Ds\\Map |
+ * | NULL | null** |
+ *
+ * (*) If an application does not explicitly specify an Ignite type for a field and
+ * COMPLEX_OBJECT is received, the Ignite client returns BinaryObject to the application.
+ * If an application explicitly specifies ComplexObjectType for a field,
+ * the Ignite client deserializes the received COMPLEX_OBJECT into PHP object
+ * specified by the ComplexObjectType.
+ *
+ * (**) NULL cannot be specified as an Ignite type of a field but PHP null may be returned
+ * as a value of a field.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * DEFAULT MAPPING FROM PHP TYPE TO IGNITE TYPE CODE WHEN WRITING DATA
+ * ----------------
+ *
+ * This mapping is used when an application does not explicitly specify an Ignite type
+ * for a field and it is writing data to that field.
+ *
+ * | PHP type | Ignite type code |
+ * | ------------------------------------------- | ----------------------|
+ * | boolean | BOOLEAN |
+ * | integer | INTEGER |
+ * | float | DOUBLE |
+ * | string | STRING |
+ * | Date | DATE |
+ * | Time | TIME |
+ * | Timestamp | TIMESTAMP |
+ * | EnumItem | ENUM |
+ * | Brick\\Math\\BigDecimal | DECIMAL |
+ * | BinaryObject | COMPLEX_OBJECT |
+ * | any other PHP Object* | COMPLEX_OBJECT |
+ * | associative array of PHP supported type** | MAP (HASH_MAP) |
+ * | indexed array of boolean*** | BOOLEAN_ARRAY |
+ * | indexed array of integer | INTEGER_ARRAY |
+ * | indexed array of float | DOUBLE_ARRAY |
+ * | indexed array of string | STRING_ARRAY |
+ * | indexed array of Date | DATE_ARRAY |
+ * | indexed array of Time | TIME_ARRAY |
+ * | indexed array of Timestamp | TIMESTAMP_ARRAY |
+ * | indexed array of EnumItem | ENUM_ARRAY |
+ * | indexed array of Brick\\Math\\BigDecimal | DECIMAL_ARRAY |
+ * | indexed array of BinaryObject | OBJECT_ARRAY |
+ * | indexed array of any other PHP Object* | OBJECT_ARRAY |
+ * | Ds\\Set | COLLECTION (HASH_SET) |
+ * | Ds\\Map | MAP (HASH_MAP) |
+ *
+ * All other PHP types have no default mapping to Ignite type codes.
+ *
+ * (*) Any other PHP Object - is any PHP class, not explicitly mentioned in the table.
+ *
+ * (**) PHP supported type - is any PHP type mentioned in the table.
+ *
+ * (***) Type of an indexed array's value is determined by the value's type in the first element of the array.
+ * Empty array has no default mapping.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * ALLOWED PHP TYPES WHEN WRITING DATA OF THE SPECIFIED IGNITE TYPE CODE
+ * ----------------
+ *
+ * When an application explicitly specifies an Ignite type for a field
+ * and it is writing data to that field, the following PHP types
+ * are allowed for every concrete Ignite type code.
+ *
+ * | Specified Ignite type code | Allowed PHP types |
+ * | ---------------------------- | ----------------------------------------------|
+ * | BYTE | integer |
+ * | SHORT | integer |
+ * | INTEGER | integer |
+ * | LONG | float, integer |
+ * | FLOAT | float, integer |
+ * | DOUBLE | float, integer |
+ * | DECIMAL | Brick\\Math\\BigDecimal |
+ * | BOOLEAN | boolean |
+ * | STRING | string |
+ * | CHAR | string (one character) |
+ * | UUID | indexed array of integers (16 items) |
+ * | DATE | Date |
+ * | TIME | Time |
+ * | TIMESTAMP | Timestamp |
+ * | ENUM | EnumItem |
+ * | COMPLEX_OBJECT | BinaryObject, any PHP object |
+ * | BYTE_ARRAY* | indexed array of integer |
+ * | SHORT_ARRAY | indexed array of integer |
+ * | INTEGER_ARRAY | indexed array of integer |
+ * | LONG_ARRAY | indexed array of float/integer |
+ * | FLOAT_ARRAY | indexed array of float/integer |
+ * | DOUBLE_ARRAY | indexed array of float/integer |
+ * | DECIMAL_ARRAY | indexed array of Brick\\Math\\BigDecimal |
+ * | BOOLEAN_ARRAY | indexed array of boolean |
+ * | STRING_ARRAY | indexed array of string |
+ * | CHAR_ARRAY | indexed array of string (one character) |
+ * | UUID_ARRAY | indexed array of array of integers (16 items) |
+ * | DATE_ARRAY | indexed array of Date |
+ * | TIME_ARRAY | indexed array of Time |
+ * | TIMESTAMP_ARRAY | indexed array of Timestamp |
+ * | ENUM_ARRAY | indexed array of EnumItem |
+ * | OBJECT_ARRAY | indexed array |
+ * | COLLECTION (USER_COL) | indexed array |
+ * | COLLECTION (ARR_LIST) | indexed array |
+ * | COLLECTION (LINKED_LIST) | indexed array |
+ * | COLLECTION (SINGLETON_LIST) | indexed array |
+ * | COLLECTION (HASH_SET) | Ds\\Set |
+ * | COLLECTION (LINKED_HASH_SET) | Ds\\Set |
+ * | COLLECTION (USER_SET) | Ds\\Set |
+ * | MAP (HASH_MAP) | Ds\\Map, associative array |
+ * | MAP (LINKED_HASH_MAP) | Ds\\Map, associative array |
+ *
+ * (*) For all *_ARRAY Ignite types an empty PHP indexed array is allowed.
+ *
+ * PHP null is allowed as value of a field (but not as a key/value in a cache)
+ * or as a value of Array/Set/Map element for all Ignite types,
+ * except BYTE, SHORT, INTEGER, LONG, FLOAT, DOUBLE, CHAR, BOOLEAN.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ */
+abstract class ObjectType
+{
+ /** @name PrimitiveTypeCodes
+ * @anchor PrimitiveTypeCodes
+ * @{
+ */
+
+ /**
+ * Single byte value. Can also represent small signed integer value.
+ */
+ const BYTE = 1;
+
+ /**
+ * 2-bytes long signed integer number.
+ */
+ const SHORT = 2;
+
+ /**
+ * 4-bytes long signed integer number.
+ */
+ const INTEGER = 3;
+
+ /**
+ * 8-bytes long signed integer number.
+ */
+ const LONG = 4;
+
+ /**
+ * 4-byte long floating-point number.
+ */
+ const FLOAT = 5;
+
+ /**
+ * 8-byte long floating-point number.
+ */
+ const DOUBLE = 6;
+
+ /**
+ * Single UTF-16 code unit.
+ */
+ const CHAR = 7;
+
+ /**
+ * Boolean value.
+ */
+ const BOOLEAN = 8;
+
+ /**
+ * String in UTF-8 encoding.
+ */
+ const STRING = 9;
+
+ /**
+ * A universally unique identifier (UUID) is a 128-bit number used to identify information in computer systems.
+ */
+ const UUID = 10;
+
+ /**
+ * Date, represented as a number of milliseconds elapsed since 00:00:00 1 Jan 1970 UTC.
+ */
+ const DATE = 11;
+
+ /**
+ * Array of bytes.
+ */
+ const BYTE_ARRAY = 12;
+
+ /**
+ * Array of short signed integer numbers.
+ */
+ const SHORT_ARRAY = 13;
+
+ /**
+ * Array of signed integer numbers.
+ */
+ const INTEGER_ARRAY = 14;
+
+ /**
+ * Array of long signed integer numbers.
+ */
+ const LONG_ARRAY = 15;
+
+ /**
+ * Array of floating point numbers.
+ */
+ const FLOAT_ARRAY = 16;
+
+ /**
+ * Array of floating point numbers with double precision.
+ */
+ const DOUBLE_ARRAY = 17;
+
+ /**
+ * Array of UTF-16 code units.
+ */
+ const CHAR_ARRAY = 18;
+
+ /**
+ * Array of boolean values.
+ */
+ const BOOLEAN_ARRAY = 19;
+
+ /**
+ * Array of UTF-8 string values.
+ */
+ const STRING_ARRAY = 20;
+
+ /**
+ * Array of UUIDs.
+ */
+ const UUID_ARRAY = 21;
+
+ /**
+ * Array of dates.
+ */
+ const DATE_ARRAY = 22;
+
+ /**
+ * Value of an enumerable type. For such types defined only a finite number of named values.
+ */
+ const ENUM = 28;
+
+ /**
+ * Array of enumerable type value.
+ */
+ const ENUM_ARRAY = 29;
+
+ /**
+ * Numeric value of any desired precision and scale.
+ */
+ const DECIMAL = 30;
+
+ /**
+ * Array of decimal values.
+ */
+ const DECIMAL_ARRAY = 31;
+
+ /**
+ * More precise than a Date data type. Except for a milliseconds since epoch, contains a nanoseconds
+ * fraction of a last millisecond, which value could be in a range from 0 to 999999.
+ */
+ const TIMESTAMP = 33;
+
+ /**
+ * Array of timestamp values.
+ */
+ const TIMESTAMP_ARRAY = 34;
+
+ /**
+ * Time, represented as a number of milliseconds elapsed since midnight, i.e. 00:00:00 UTC.
+ */
+ const TIME = 36;
+
+ /**
+ * Array of time values.
+ */
+ const TIME_ARRAY = 37;
+ /** @} */ // end of PrimitiveTypeCodes
+
+ /** @name CompositeTypeCodes
+ * @anchor CompositeTypeCodes
+ * @{
+ */
+ /**
+ * Array of objects of any type.
+ */
+ const OBJECT_ARRAY = 23;
+
+ /**
+ * General collection type.
+ */
+ const COLLECTION = 24;
+
+ /**
+ * Map-like collection type. Contains pairs of key and value objects.
+ */
+ const MAP = 25;
+
+ /**
+ * Wrapped binary object type.
+ */
+ const BINARY_OBJECT = 27;
+
+ /**
+ * Wrapped enumerable type.
+ */
+ const BINARY_ENUM = 38;
+
+ /**
+ * null value.
+ */
+ const NULL = 101;
+
+ /**
+ * Complex object.
+ */
+ const COMPLEX_OBJECT = 103;
+ /** @} */ // end of CompositeTypeCodes
+
+ private $typeCode;
+
+ /**
+ * Gets Ignite type code of this Ignite object type.
+ *
+ * @return int Ignite type code
+ */
+ public function getTypeCode(): int
+ {
+ return $this->typeCode;
+ }
+
+ //The class is abstract and has no public constructor. Only subclasses may be instantiated.
+ protected function __construct(int $typeCode)
+ {
+ $this->typeCode = $typeCode;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/tests/BinaryObjectTest.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/BinaryObjectTest.php b/modules/platforms/php/tests/BinaryObjectTest.php
new file mode 100644
index 0000000..c5ca517
--- /dev/null
+++ b/modules/platforms/php/tests/BinaryObjectTest.php
@@ -0,0 +1,196 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Data\BinaryObject;
+use Apache\Ignite\Data\Date;
+
+final class BinaryObjectTestCase extends TestCase
+{
+ const CACHE_NAME = '__php_test_cache';
+
+ const TYPE_NAME = 'TestClass';
+ const INNER_TYPE_NAME = 'InnerTestClass';
+ const STRING_VALUE = 'abc';
+ const DOUBLE_VALUE = 123.45;
+ const BOOL_VALUE = false;
+ const INT_VALUE = 456;
+
+ private static $cache;
+
+ public static function setUpBeforeClass(): void
+ {
+ TestingHelper::init();
+ self::cleanUp();
+ self::$cache = TestingHelper::$client->getOrCreateCache(self::CACHE_NAME);
+ }
+
+ public static function tearDownAfterClass(): void
+ {
+ self::cleanUp();
+ TestingHelper::cleanUp();
+ }
+
+ public function testBinaryObjectSetGetFields(): void
+ {
+ $cache = self::$cache;
+ try {
+ $obj1 = new BinaryObject(self::TYPE_NAME);
+ $obj1->setField('field_double', self::DOUBLE_VALUE);
+ $obj1->setField('field_string', self::STRING_VALUE);
+
+ $cache->put(2, $obj1);
+ $cache->put(3, $obj1);
+ $obj2 = $cache->get(2);
+ $this->assertTrue(TestingHelper::compare($obj1, $obj2));
+
+ $obj2->setField('field_double', $obj1->getField('field_double'));
+ $obj2->setField('field_string', $obj1->getField('field_string'));
+ $this->assertTrue(TestingHelper::compare($obj1, $obj2));
+
+ $obj3 = $cache->get(3);
+ $obj1->setField('field_double', $obj3->getField('field_double'));
+ $obj1->setField('field_string', $obj3->getField('field_string'));
+ $this->assertTrue(TestingHelper::compare($obj1, $obj3));
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testBinaryObjectGetNonexistentField(): void
+ {
+ $cache = self::$cache;
+ try {
+ $obj1 = new BinaryObject(self::TYPE_NAME);
+ $obj1->setField('field_double', self::DOUBLE_VALUE);
+ $obj1->setField('field_string', self::STRING_VALUE);
+
+ $this->expectException(ClientException::class);
+ $obj1->getField('field_bool');
+
+ $cache->put(2, $obj1);
+ $obj2 = $cache->get(2);
+ $obj2->getField('field_bool');
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testBinaryObjectRemoveField(): void
+ {
+ $cache = self::$cache;
+ try {
+ $obj1 = new BinaryObject(self::TYPE_NAME);
+ $obj1->setField('field_double', self::DOUBLE_VALUE);
+ $obj1->setField('field_string', self::STRING_VALUE);
+ $obj1->setField('field_bool', self::BOOL_VALUE);
+ $this->assertTrue($obj1->hasField('field_bool'));
+ $this->assertEquals($obj1->getField('field_bool'), self::BOOL_VALUE);
+
+ $obj1->removeField('field_bool');
+ $this->assertFalse($obj1->hasField('field_bool'));
+
+ $cache->put(3, $obj1);
+ $obj2 = $cache->get(3);
+ $this->assertTrue(TestingHelper::compare($obj1, $obj2));
+
+ $obj2->setField('field_bool', self::BOOL_VALUE);
+ $this->assertTrue($obj2->hasField('field_bool'));
+ $this->assertEquals($obj2->getField('field_bool'), self::BOOL_VALUE);
+
+ $obj2->removeField('field_bool');
+ $this->assertFalse($obj2->hasField('field_bool'));
+
+ $obj2->setField('field_bool', self::BOOL_VALUE);
+ $cache->put(4, $obj2);
+
+ $obj1->setField('field_bool', self::BOOL_VALUE);
+ $cache->put(5, $obj1);
+
+ $this->assertTrue(TestingHelper::compare($cache->get(4), $cache->get(5)));
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testBinaryObjectOfDifferentSchemas(): void
+ {
+ $cache = self::$cache;
+ try {
+ $obj1 = new BinaryObject(self::TYPE_NAME);
+ $obj1->setField('field_int', self::INT_VALUE);
+ $obj1->setField('field_string', self::STRING_VALUE);
+ $obj1->setField('field_bool', self::BOOL_VALUE);
+ $cache->put(1, $obj1);
+
+ $obj2 = new BinaryObject(self::TYPE_NAME);
+ $obj2->setField('field_int', self::INT_VALUE);
+ $obj2->setField('field_bool', self::BOOL_VALUE);
+ $obj2->setField('field_date', new Date(12345));
+ $cache->put(2, $obj2);
+
+ $obj3 = $cache->get(1);
+ $obj3->removeField('field_string');
+ $obj4 = $cache->get(2);
+ $obj4->removeField('field_date');
+ $this->assertTrue(TestingHelper::compare($obj3, $obj4));
+
+ $cache->put(3, $obj3);
+ $cache->put(4, $obj4);
+ $this->assertTrue(TestingHelper::compare($cache->get(3), $cache->get(4)));
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testNestedBinaryObjects(): void
+ {
+ $cache = self::$cache;
+ try {
+ $obj2 = new BinaryObject(self::INNER_TYPE_NAME);
+ $obj2->setField('field_int', self::INT_VALUE);
+ $obj2->setField('field_date', new Date(1234567));
+
+ $obj1 = new BinaryObject(self::TYPE_NAME);
+ $obj1->setField('field_double', self::DOUBLE_VALUE);
+ $obj1->setField('field_string', self::STRING_VALUE);
+ $obj1->setField('field_object', $obj2);
+
+ $cache->put(1, $obj1);
+ $obj3 = $cache->get(1);
+ $obj4 = $obj3->getField('field_object');
+ $obj4->setField('field_int', $obj4->getField('field_int') + 1);
+ $obj3->setField('field_object', $obj4);
+ $cache->put(3, $obj3);
+
+ $obj2->setField('field_int', self::INT_VALUE + 1);
+ $obj1->setField('field_object', $obj2);
+ $this->assertTrue(TestingHelper::compare($cache->get(3), $obj1));
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ private static function cleanUp(): void
+ {
+ TestingHelper::destroyCache(self::CACHE_NAME);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/tests/CacheKeyValueOpsTest.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/CacheKeyValueOpsTest.php b/modules/platforms/php/tests/CacheKeyValueOpsTest.php
new file mode 100644
index 0000000..b7e1dea
--- /dev/null
+++ b/modules/platforms/php/tests/CacheKeyValueOpsTest.php
@@ -0,0 +1,763 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Cache\CacheEntry;
+use Apache\Ignite\Cache\CacheConfiguration;
+use Apache\Ignite\Cache\CacheInterface;
+
+final class CacheKeyValueOpsTestCase extends TestCase
+{
+ const CACHE_NAME = '__php_test_cache';
+
+ public static function setUpBeforeClass(): void
+ {
+ TestingHelper::init();
+ self::cleanUp();
+ TestingHelper::$client->getOrCreateCache(self::CACHE_NAME);
+ }
+
+ public static function tearDownAfterClass(): void
+ {
+ self::cleanUp();
+ TestingHelper::cleanUp();
+ }
+
+ public function testCacheGet(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $value = $cache->get(1);
+ $this->assertEquals($value, null);
+ $cache->put(1, 2);
+ $value = $cache->get(1);
+ $this->assertEquals($value, 2);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function cacheWrongKeys(): array
+ {
+ return array(
+ array(null)
+ );
+ }
+
+ /**
+ * @dataProvider cacheWrongKeys
+ */
+ public function testCacheGetWrongArgs($cacheKey): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->get($cacheKey);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheGetAll(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ for ($i = 0; $i < 5; $i++) {
+ $cache->put($i, $i * 2);
+ }
+ $entries = $cache->getAll([3, 4, 5, 6, 7]);
+ $this->assertCount(2, $entries);
+ foreach ($entries as $entry) {
+ $this->assertTrue($entry->getKey() === 3 || $entry->getKey() === 4);
+ $this->assertEquals($entry->getValue(), $entry->getKey() * 2);
+ }
+ $entries = $cache->getAll([6, 7, 8]);
+ $this->assertCount(0, $entries);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function cacheGetAllWrongKeys(): array
+ {
+ return array(
+ array([])
+ );
+ }
+
+ /**
+ * @dataProvider cacheGetAllWrongKeys
+ */
+ public function testCacheGetAllWrongArgs($keys): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->getAll($keys);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCachePut(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $value = $cache->get(1);
+ $this->assertEquals($value, null);
+ $cache->put(1, 2);
+ $value = $cache->get(1);
+ $this->assertEquals($value, 2);
+ $cache->put(1, 4);
+ $value = $cache->get(1);
+ $this->assertEquals($value, 4);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function cacheWrongKeyValues(): array
+ {
+ return array(
+ array(null, 1),
+ array(1, null),
+ array(null, null)
+ );
+ }
+
+ /**
+ * @dataProvider cacheWrongKeyValues
+ */
+ public function testCachePutWrongArgs($key, $value): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->put($key, $value);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCachePutAll(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $cacheEntries = array();
+ for ($i = 0; $i < 5; $i++) {
+ array_push($cacheEntries, new CacheEntry($i, $i * 2));
+ }
+ $cache->putAll($cacheEntries);
+ $entries = $cache->getAll([3, 4, 5, 6, 7]);
+ $this->assertCount(2, $entries);
+ foreach ($entries as $entry) {
+ $this->assertTrue($entry->getKey() === 3 || $entry->getKey() === 4);
+ $this->assertEquals($entry->getValue(), $entry->getKey() * 2);
+ }
+ $entries = $cache->getAll([-2, -1, 0, 1, 2, 3, 4, 5, 6, 7]);
+ $this->assertCount(5, $entries);
+ foreach ($entries as $entry) {
+ $this->assertTrue($entry->getKey() >= 0 && $entry->getKey() <= 4);
+ $this->assertEquals($entry->getValue(), $entry->getKey() * 2);
+ }
+ $entries = $cache->getAll([6, 7, 8]);
+ $this->assertCount(0, $entries);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function cachePutAllWrongArgs(): array
+ {
+ return array(
+ array([]),
+ array([new CacheConfiguration])
+ );
+ }
+
+ /**
+ * @dataProvider cachePutAllWrongArgs
+ */
+ public function testCachePutAllWrongArgs($entries): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->putAll($entries);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testContainsKey(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $result = $cache->containsKey(1);
+ $this->assertFalse($result);
+ $cache->put(1, 2);
+ $result = $cache->containsKey(1);
+ $this->assertTrue($result);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ /**
+ * @dataProvider cacheWrongKeys
+ */
+ public function testContainsKeyWrongArgs($cacheKey): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->containsKey($cacheKey);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheContainsKeys(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $result = $cache->containsKeys([1, 2, 3]);
+ $this->assertFalse($result);
+ $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4)]);
+ $result = $cache->containsKeys([1, 2, 3]);
+ $this->assertFalse($result);
+ $cache->put(3, 6);
+ $result = $cache->containsKeys([1, 2, 3]);
+ $this->assertTrue($result);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ /**
+ * @dataProvider cacheGetAllWrongKeys
+ */
+ public function testCacheContainsKeysWrongArgs($keys): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->containsKeys($keys);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheGetAndPut(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $value = $cache->getAndPut(1, 2);
+ $this->assertEquals($value, null);
+ $value = $cache->getAndPut(1, 4);
+ $this->assertEquals($value, 2);
+ $cache->put(1, 6);
+ $value = $cache->getAndPut(1, 8);
+ $this->assertEquals($value, 6);
+ $value = $cache->get(1);
+ $this->assertEquals($value, 8);
+
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ /**
+ * @dataProvider cacheWrongKeyValues
+ */
+ public function testCacheGetAndPutWrongArgs($key, $value): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->getAndPut($key, $value);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheGetAndReplace(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $value = $cache->getAndReplace(1, 2);
+ $this->assertEquals($value, null);
+ $cache->put(1, 4);
+ $value = $cache->getAndReplace(1, 6);
+ $this->assertEquals($value, 4);
+ $value = $cache->get(1);
+ $this->assertEquals($value, 6);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ /**
+ * @dataProvider cacheWrongKeyValues
+ */
+ public function testCacheGetAndReplaceWrongArgs($key, $value): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->getAndReplace($key, $value);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheGetAndRemove(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $value = $cache->getAndRemove(1);
+ $this->assertEquals($value, null);
+ $cache->put(1, 2);
+ $value = $cache->getAndRemove(1);
+ $this->assertEquals($value, 2);
+ $value = $cache->get(1);
+ $this->assertEquals($value, null);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ /**
+ * @dataProvider cacheWrongKeys
+ */
+ public function testCacheGetAndRemoveWrongArgs($cacheKey): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->getAndRemove($cacheKey);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCachePutIfAbsent(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $result = $cache->putIfAbsent(1, 2);
+ $this->assertTrue($result);
+ $value = $cache->get(1);
+ $this->assertEquals($value, 2);
+ $result = $cache->putIfAbsent(1, 4);
+ $this->assertFalse($result);
+ $value = $cache->get(1);
+ $this->assertEquals($value, 2);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ /**
+ * @dataProvider cacheWrongKeyValues
+ */
+ public function testCachePutIfAbsentWrongArgs($key, $value): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->putIfAbsent($key, $value);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheGetAndPutIfAbsent(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $value = $cache->getAndPutIfAbsent(1, 2);
+ $this->assertEquals($value, null);
+ $value = $cache->get(1);
+ $this->assertEquals($value, 2);
+ $value = $cache->getAndPutIfAbsent(1, 4);
+ $this->assertEquals($value, 2);
+ $value = $cache->get(1);
+ $this->assertEquals($value, 2);
+
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ /**
+ * @dataProvider cacheWrongKeyValues
+ */
+ public function testCacheGetAndPutIfAbsentWrongArgs($key, $value): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->getAndPutIfAbsent($key, $value);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheReplace(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $result = $cache->replace(1, 2);
+ $this->assertFalse($result);
+ $value = $cache->get(1);
+ $this->assertEquals($value, null);
+ $cache->put(1, 1);
+ $result = $cache->replace(1, 4);
+ $this->assertTrue($result);
+ $value = $cache->get(1);
+ $this->assertEquals($value, 4);
+
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ /**
+ * @dataProvider cacheWrongKeyValues
+ */
+ public function testCacheReplaceWrongArgs($key, $value): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->replace($key, $value);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheReplaceIfEquals(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $result = $cache->replaceIfEquals(1, 2, 3);
+ $this->assertFalse($result);
+ $cache->put(1, 4);
+ $result = $cache->replaceIfEquals(1, 2, 3);
+ $this->assertFalse($result);
+ $value = $cache->get(1);
+ $this->assertEquals($value, 4);
+ $result = $cache->replaceIfEquals(1, 4, 3);
+ $this->assertTrue($result);
+ $value = $cache->get(1);
+ $this->assertEquals($value, 3);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function cacheWrongReplaceIfEqualsArgs(): array
+ {
+ return array(
+ array(null, 1, 1),
+ array(null, 1, null),
+ array(1, null, 1),
+ array(1, null, null),
+ array(null, null, null)
+ );
+ }
+
+ /**
+ * @dataProvider cacheWrongReplaceIfEqualsArgs
+ */
+ public function testCacheReplaceIfEqualsWrongArgs($key, $value, $newValue): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->replaceIfEquals($key, $value, $newValue);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheClear(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $cache->clear();
+ $result = $cache->getSize();
+ $this->assertEquals($result, 0);
+ $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 3);
+ $cache->clear();
+ $result = $cache->getSize();
+ $this->assertEquals($result, 0);
+ $entries = $cache->getAll([1, 2, 3]);
+ $this->assertCount(0, $entries);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheClearKeys(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $cache->clearKeys([1, 2, 3]);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 0);
+ $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 3);
+ $cache->clearKeys([1, 2, 7, 8]);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 1);
+ $value = $cache->get(3);
+ $this->assertEquals($value, 6);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ /**
+ * @dataProvider cacheGetAllWrongKeys
+ */
+ public function testCacheClearKeysWrongArgs($keys): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->clearKeys($keys);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheClearKey(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $cache->clearKey(1);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 0);
+ $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 3);
+ $cache->clearKey(1);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 2);
+ $value = $cache->get(2);
+ $this->assertEquals($value, 4);
+ $value = $cache->get(3);
+ $this->assertEquals($value, 6);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ /**
+ * @dataProvider cacheWrongKeys
+ */
+ public function testCacheClearKeyWrongArgs($cacheKey): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->clearKey($cacheKey);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheRemoveKey(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $result = $cache->removeKey(1);
+ $this->assertFalse($result);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 0);
+ $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 3);
+ $result = $cache->removeKey(1);
+ $this->assertTrue($result);
+ $result = $cache->removeKey(1);
+ $this->assertFalse($result);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 2);
+ $value = $cache->get(2);
+ $this->assertEquals($value, 4);
+ $value = $cache->get(3);
+ $this->assertEquals($value, 6);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ /**
+ * @dataProvider cacheWrongKeys
+ */
+ public function testCacheRemoveKeyWrongArgs($cacheKey): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->removeKey($cacheKey);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testRemoveIfEquals(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $result = $cache->removeIfEquals(1, 2);
+ $this->assertFalse($result);
+ $cache->put(1, 4);
+ $result = $cache->removeIfEquals(1, 2);
+ $this->assertFalse($result);
+ $result = $cache->removeIfEquals(1, 4);
+ $this->assertTrue($result);
+ $value = $cache->get(1);
+ $this->assertEquals($value, null);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ /**
+ * @dataProvider cacheWrongKeyValues
+ */
+ public function testRemoveIfEqualsWrongArgs($key, $value): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->removeIfEquals($key, $value);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheRemoveKeys(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $cache->removeKeys([1, 2, 3]);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 0);
+ $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 3);
+ $cache->removeKeys([1, 2, 7, 8]);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 1);
+ $value = $cache->get(3);
+ $this->assertEquals($value, 6);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ /**
+ * @dataProvider cacheGetAllWrongKeys
+ */
+ public function testCacheRemoveKeysWrongArgs($keys): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->removeKeys($keys);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheRemoveAll(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $cache->removeAll();
+ $result = $cache->getSize();
+ $this->assertEquals($result, 0);
+ $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 3);
+ $cache->removeAll();
+ $result = $cache->getSize();
+ $this->assertEquals($result, 0);
+ $entries = $cache->getAll([1, 2, 3]);
+ $this->assertCount(0, $entries);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function testCacheGetSize(): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $result = $cache->getSize();
+ $this->assertEquals($result, 0);
+ $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+ $result = $cache->getSize();
+ $this->assertEquals($result, 3);
+ $result = $cache->getSize(CacheInterface::PEEK_MODE_ALL);
+ $this->assertEquals($result, 3);
+ $result = $cache->getSize(CacheInterface::PEEK_MODE_ALL, CacheInterface::PEEK_MODE_ALL);
+ $this->assertEquals($result, 3);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ public function getSizeWrongArgs(): array
+ {
+ return array(
+ array(-1, -2),
+ array(4, 5, 6, 0)
+ );
+ }
+
+ /**
+ * @dataProvider getSizeWrongArgs
+ */
+ public function testCacheGetSizeWrongArgs($modes): void
+ {
+ $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+ try {
+ $this->expectException(ClientException::class);
+ $cache->getSize($modes);
+ } finally {
+ $cache->removeAll();
+ }
+ }
+
+ private static function cleanUp(): void
+ {
+ TestingHelper::destroyCache(self::CACHE_NAME);
+ }
+}
[2/9] ignite git commit: IGNITE-7783: PHP thin client
Posted by is...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/tests/CachePutGetTest.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/CachePutGetTest.php b/modules/platforms/php/tests/CachePutGetTest.php
new file mode 100644
index 0000000..9d15ab2
--- /dev/null
+++ b/modules/platforms/php/tests/CachePutGetTest.php
@@ -0,0 +1,646 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+use Ds\Map;
+use Ds\Set;
+use PHPUnit\Framework\TestCase;
+use Apache\Ignite\Type\MapObjectType;
+use Apache\Ignite\Type\CollectionObjectType;
+use Apache\Ignite\Type\ObjectArrayType;
+use Apache\Ignite\Type\ComplexObjectType;
+use Apache\Ignite\Data\BinaryObject;
+
+class TstComplObjectWithPrimitiveFields
+{
+ public $field1;
+ public $field2;
+ public $field3;
+ public $field4;
+ public $field5;
+ public $field6;
+ public $field7;
+ public $field8;
+ public $field9;
+ public $field10;
+ public $field11;
+ public $field30;
+ public $field33;
+ public $field36;
+}
+
+class TstComplObjectWithDefaultFieldTypes
+{
+ public $field3;
+ public $field6;
+ public $field8;
+ public $field9;
+ public $field11;
+ public $field30;
+ public $field33;
+ public $field36;
+}
+
+final class CachePutGetTestCase extends TestCase
+{
+ const CACHE_NAME = '__php_test_cache';
+
+ private static $cache;
+
+ public static function setUpBeforeClass(): void
+ {
+ TestingHelper::init();
+ self::cleanUp();
+ self::$cache = TestingHelper::$client->getOrCreateCache(self::CACHE_NAME);
+ }
+
+ public static function tearDownAfterClass(): void
+ {
+ self::cleanUp();
+ TestingHelper::cleanUp();
+ }
+
+ public function testPutGetPrimitiveValues(): void
+ {
+ foreach (TestingHelper::$primitiveValues as $typeCode1 => $typeInfo1) {
+ foreach (TestingHelper::$primitiveValues as $typeCode2 => $typeInfo2) {
+ foreach ($typeInfo1['values'] as $value1) {
+ foreach ($typeInfo2['values'] as $value2) {
+ $this->putGetPrimitiveValues($typeCode1, $typeCode2, $value1, $value2);
+ if (array_key_exists('typeOptional', $typeInfo1)) {
+ $this->putGetPrimitiveValues(null, $typeCode2, $value1, $value2);
+ }
+ if (array_key_exists('typeOptional', $typeInfo2)) {
+ $this->putGetPrimitiveValues($typeCode1, null, $value1, $value2);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public function testPutGetArraysOfPrimitives(): void
+ {
+ foreach (TestingHelper::$arrayValues as $type => $typeInfo) {
+ $primitiveType = $typeInfo['elemType'];
+ $values = TestingHelper::$primitiveValues[$primitiveType]['values'];
+ $this->putGetArrays($primitiveType, $type, $values[0], $values);
+ $this->putGetArrays($primitiveType, $type, $values[0], []);
+ if (array_key_exists('typeOptional', $typeInfo)) {
+ $this->putGetArrays($primitiveType, $type, $values[0], $values);
+ }
+ }
+ }
+
+ public function testPutGetMaps(): void
+ {
+ foreach (TestingHelper::$primitiveValues as $type1 => $typeInfo1) {
+ if (!$typeInfo1['isMapKey']) {
+ continue;
+ }
+ foreach (TestingHelper::$primitiveValues as $type2 => $typeInfo2) {
+ $map = new Map();
+ $index2 = 0;
+ foreach ($typeInfo1['values'] as $value1) {
+ $value2 = $typeInfo2['values'][$index2];
+ $index2++;
+ if ($index2 >= count($typeInfo2['values'])) {
+ $index2 = 0;
+ }
+ $map->put($value1, $value2);
+ }
+ $this->putGetMaps(new MapObjectType(MapObjectType::HASH_MAP, $type1, $type2), $map);
+ $this->putGetMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP, $type1, $type2), $map);
+ if (array_key_exists('typeOptional', $typeInfo1)) {
+ $this->putGetMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP, null, $type2), $map);
+ }
+ if (array_key_exists('typeOptional', $typeInfo2)) {
+ $this->putGetMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP, $type1), $map);
+ }
+ if (array_key_exists('typeOptional', $typeInfo1) && array_key_exists('typeOptional', $typeInfo2)) {
+ $this->putGetMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP), $map);
+ $this->putGetMaps(null, $map);
+ }
+ }
+ }
+ }
+
+ public function testPutGetArrayMaps(): void
+ {
+ foreach (TestingHelper::$primitiveValues as $type1 => $typeInfo1) {
+ if (!$typeInfo1['isArrayKey']) {
+ continue;
+ }
+ foreach (TestingHelper::$primitiveValues as $type2 => $typeInfo2) {
+ $map = [];
+ $index2 = 0;
+ foreach ($typeInfo1['values'] as $value1) {
+ $value2 = $typeInfo2['values'][$index2];
+ $index2++;
+ if ($index2 >= count($typeInfo2['values'])) {
+ $index2 = 0;
+ }
+ $map[$value1] = $value2;
+ }
+ $this->putGetArrayMaps(new MapObjectType(MapObjectType::HASH_MAP, $type1, $type2), $map);
+ $this->putGetArrayMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP, $type1, $type2), $map);
+ if (array_key_exists('typeOptional', $typeInfo1)) {
+ $this->putGetArrayMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP, null, $type2), $map);
+ }
+ if (array_key_exists('typeOptional', $typeInfo2)) {
+ $this->putGetArrayMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP, $type1), $map);
+ }
+ if (array_key_exists('typeOptional', $typeInfo1) && array_key_exists('typeOptional', $typeInfo2)) {
+ $this->putGetArrayMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP), $map);
+ $this->putGetArrayMaps(null, $map);
+ }
+ }
+ }
+ }
+
+ public function testPutGetMapsWithArrays(): void
+ {
+ foreach (TestingHelper::$primitiveValues as $type1 => $typeInfo1) {
+ if (!$typeInfo1['isMapKey']) {
+ continue;
+ }
+ foreach (TestingHelper::$arrayValues as $type2 => $typeInfo2) {
+ $primitiveType2 = $typeInfo2['elemType'];
+ $values2 = TestingHelper::$primitiveValues[$primitiveType2]['values'];
+ $map = new Map();
+ $index2 = 0;
+ $arrayValues2 = [$values2, null, array_reverse($values2)];
+ foreach ($typeInfo1['values'] as $value1) {
+ $map->put($value1, $arrayValues2[$index2]);
+ $index2++;
+ if ($index2 >= count($arrayValues2)) {
+ $index2 = 0;
+ }
+ }
+ $this->putGetMaps(new MapObjectType(MapObjectType::HASH_MAP, $type1, $type2), $map);
+ $this->putGetMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP, $type1, $type2), $map);
+ if (array_key_exists('typeOptional', $typeInfo1)) {
+ $this->putGetMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP, null, $type2), $map);
+ }
+ if (array_key_exists('typeOptional', $typeInfo2)) {
+ $this->putGetMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP, $type1), $map);
+ }
+ if (array_key_exists('typeOptional', $typeInfo1) && array_key_exists('typeOptional', $typeInfo2)) {
+ $this->putGetMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP), $map);
+ $this->putGetMaps(null, $map);
+ }
+ }
+ }
+ }
+
+ public function testPutGetArrayMapsWithArrays(): void
+ {
+ foreach (TestingHelper::$primitiveValues as $type1 => $typeInfo1) {
+ if (!$typeInfo1['isArrayKey']) {
+ continue;
+ }
+ foreach (TestingHelper::$arrayValues as $type2 => $typeInfo2) {
+ $primitiveType2 = $typeInfo2['elemType'];
+ $values2 = TestingHelper::$primitiveValues[$primitiveType2]['values'];
+ $map = [];
+ $index2 = 0;
+ $arrayValues2 = [$values2, null, array_reverse($values2)];
+ foreach ($typeInfo1['values'] as $value1) {
+ $map[$value1] = $arrayValues2[$index2];
+ $index2++;
+ if ($index2 >= count($arrayValues2)) {
+ $index2 = 0;
+ }
+ }
+ $this->putGetArrayMaps(new MapObjectType(MapObjectType::HASH_MAP, $type1, $type2), $map);
+ $this->putGetArrayMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP, $type1, $type2), $map);
+ if (array_key_exists('typeOptional', $typeInfo1)) {
+ $this->putGetArrayMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP, null, $type2), $map);
+ }
+ if (array_key_exists('typeOptional', $typeInfo2)) {
+ $this->putGetArrayMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP, $type1), $map);
+ }
+ if (array_key_exists('typeOptional', $typeInfo1) && array_key_exists('typeOptional', $typeInfo2)) {
+ $this->putGetArrayMaps(new MapObjectType(MapObjectType::LINKED_HASH_MAP), $map);
+ $this->putGetArrayMaps(null, $map);
+ }
+ }
+ }
+ }
+
+ public function testPutGetSets(): void
+ {
+ foreach (TestingHelper::$primitiveValues as $type => $typeInfo) {
+ $set = new Set();
+ foreach ($typeInfo['values'] as $value) {
+ $set->add($value);
+ }
+ $this->putGetSets(new CollectionObjectType(CollectionObjectType::USER_SET, $type), $set);
+ $this->putGetSets(new CollectionObjectType(CollectionObjectType::HASH_SET, $type), $set);
+ $this->putGetSets(new CollectionObjectType(CollectionObjectType::LINKED_HASH_SET, $type), $set);
+ if (array_key_exists('typeOptional', $typeInfo)) {
+ $this->putGetSets(new CollectionObjectType(CollectionObjectType::LINKED_HASH_SET), $set);
+ $this->putGetSets(null, $set);
+ }
+ }
+ }
+
+ public function testPutGetLists(): void
+ {
+ foreach (TestingHelper::$primitiveValues as $type => $typeInfo) {
+ $list = array();
+ foreach ($typeInfo['values'] as $value) {
+ array_push($list, $value);
+ }
+ $this->putGetLists(new CollectionObjectType(CollectionObjectType::USER_COL, $type), $list);
+ $this->putGetLists(new CollectionObjectType(CollectionObjectType::ARRAY_LIST, $type), $list);
+ $this->putGetLists(new CollectionObjectType(CollectionObjectType::LINKED_LIST, $type), $list);
+ if (array_key_exists('typeOptional', $typeInfo)) {
+ $this->putGetLists(new CollectionObjectType(CollectionObjectType::ARRAY_LIST), $list);
+ }
+// $singletonList = [$typeInfo['values'][0]];
+// $this->putGetLists(new CollectionObjectType(CollectionObjectType::SINGLETON_LIST, $type), $singletonList);
+ }
+ }
+
+ public function testPutGetObjectArrayOfMaps(): void
+ {
+ foreach (TestingHelper::$primitiveValues as $type1 => $typeInfo1) {
+ if (!$typeInfo1['isMapKey']) {
+ continue;
+ }
+ foreach (TestingHelper::$primitiveValues as $type2 => $typeInfo2) {
+ $map = new Map();
+ $index2 = 0;
+ foreach ($typeInfo1['values'] as $value1) {
+ $value2 = $typeInfo2['values'][$index2];
+ $index2++;
+ if ($index2 >= count($typeInfo2['values'])) {
+ $index2 = 0;
+ }
+ $map->put($value1, $value2);
+ }
+ $array = array();
+ for ($i = 0; $i < 5; $i++) {
+ $map->reverse();
+ array_push($array, $map);
+ }
+ $this->putGetObjectArrays(new ObjectArrayType(new MapObjectType(MapObjectType::HASH_MAP, $type1, $type2)), $array);
+ if (array_key_exists('typeOptional', $typeInfo1)) {
+ $this->putGetObjectArrays(new ObjectArrayType(new MapObjectType(MapObjectType::LINKED_HASH_MAP, null, $type2)), $array);
+ }
+ if (array_key_exists('typeOptional', $typeInfo2)) {
+ $this->putGetObjectArrays(new ObjectArrayType(new MapObjectType(MapObjectType::LINKED_HASH_MAP, $type1)), $array);
+ }
+ if (array_key_exists('typeOptional', $typeInfo1) && array_key_exists('typeOptional', $typeInfo2)) {
+ $this->putGetObjectArrays(new ObjectArrayType(), $array);
+ $this->putGetObjectArrays(null, $array);
+ }
+ }
+ }
+ }
+
+ public function testPutGetObjectArrayOfPrimitives(): void
+ {
+ foreach (TestingHelper::$primitiveValues as $type => $typeInfo) {
+ $array = $typeInfo['values'];
+ $this->putGetObjectArrays(new ObjectArrayType($type), $array);
+ if (array_key_exists('typeOptional', $typeInfo)) {
+ $this->putGetObjectArrays(new ObjectArrayType(), $array);
+ }
+ }
+ }
+
+ public function testPutGetObjectArrayOfPrimitiveArrays(): void
+ {
+ foreach (TestingHelper::$arrayValues as $type => $typeInfo) {
+ $primitiveType = $typeInfo['elemType'];
+ $values = TestingHelper::$primitiveValues[$primitiveType]['values'];
+ $array = [];
+ for ($i = 0; $i < 5; $i++) {
+ $values = array_reverse($values);
+ array_push($array, $values);
+ }
+ $this->putGetObjectArrays(new ObjectArrayType($type), $array);
+ if (array_key_exists('typeOptional', $typeInfo)) {
+ $this->putGetObjectArrays(new ObjectArrayType(), $array);
+ $this->putGetObjectArrays(null, $array);
+ }
+ }
+ }
+
+ public function testPutGetObjectArrayOfSets(): void
+ {
+ foreach (TestingHelper::$primitiveValues as $type => $typeInfo) {
+ $set = new Set();
+ $values = $typeInfo['values'];
+ $array = array();
+ for ($i = 0; $i < 5; $i++) {
+ $values = array_reverse($values);
+ array_push($array, new Set($values));
+ }
+ $this->putGetObjectArrays(new ObjectArrayType(new CollectionObjectType(CollectionObjectType::USER_SET, $type)), $array);
+ $this->putGetObjectArrays(new ObjectArrayType(new CollectionObjectType(CollectionObjectType::HASH_SET, $type)), $array);
+ $this->putGetObjectArrays(new ObjectArrayType(new CollectionObjectType(CollectionObjectType::LINKED_HASH_SET, $type)), $array);
+ if (array_key_exists('typeOptional', $typeInfo)) {
+ $this->putGetObjectArrays(new ObjectArrayType(), $array);
+ $this->putGetObjectArrays(null, $array);
+ }
+ }
+ }
+
+ public function testPutGetObjectArrayOfLists(): void
+ {
+ foreach (TestingHelper::$primitiveValues as $type => $typeInfo) {
+ $set = new Set();
+ $values = $typeInfo['values'];
+ $array = array();
+ for ($i = 0; $i < 5; $i++) {
+ $values = array_reverse($values);
+ array_push($array, $values);
+ }
+ $this->putGetObjectArrays(new ObjectArrayType(new CollectionObjectType(CollectionObjectType::USER_COL, $type)), $array);
+ $this->putGetObjectArrays(new ObjectArrayType(new CollectionObjectType(CollectionObjectType::ARRAY_LIST, $type)), $array);
+ $this->putGetObjectArrays(new ObjectArrayType(new CollectionObjectType(CollectionObjectType::LINKED_LIST, $type)), $array);
+ if (array_key_exists('typeOptional', $typeInfo)) {
+ $this->putGetObjectArrays(new ObjectArrayType(new CollectionObjectType(CollectionObjectType::ARRAY_LIST)), $array);
+ }
+ }
+ }
+
+ public function testPutGetObjectArrayOfComplexObjects(): void
+ {
+ $array = array();
+ for ($i = 0; $i < 5; $i++) {
+ $object = new TstComplObjectWithPrimitiveFields();
+ foreach (TestingHelper::$primitiveValues as $type => $typeInfo) {
+ $fieldName = 'field' . $type;
+ $index = ($i < count($typeInfo['values'])) ? $i : $i % count($typeInfo['values']);
+ $object->$fieldName = $typeInfo['values'][$index];
+ }
+ array_push($array, $object);
+ }
+
+ $fullComplexObjectType = new ComplexObjectType();
+ $partComplexObjectType = new ComplexObjectType();
+ foreach (TestingHelper::$primitiveValues as $type => $typeInfo) {
+ $fullComplexObjectType->setFieldType('field' . $type, $type);
+ if (!array_key_exists('typeOptional', $typeInfo)) {
+ $partComplexObjectType->setFieldType('field' . $type, $type);
+ }
+ }
+ $this->putGetObjectArrays(new ObjectArrayType($fullComplexObjectType), $array);
+ $this->putGetObjectArrays(new ObjectArrayType($partComplexObjectType), $array);
+ }
+
+ public function testPutGetObjectArrayOfComplexObjectsWithDefaultFieldTypes(): void
+ {
+ $array = array();
+ for ($i = 0; $i < 5; $i++) {
+ $object = new TstComplObjectWithDefaultFieldTypes();
+ foreach (TestingHelper::$primitiveValues as $type => $typeInfo) {
+ if (!array_key_exists('typeOptional', $typeInfo)) {
+ continue;
+ }
+ $fieldName = 'field' . $type;
+ $index = ($i < count($typeInfo['values'])) ? $i : $i % count($typeInfo['values']);
+ $object->$fieldName = $typeInfo['values'][$index];
+ }
+ array_push($array, $object);
+ }
+ $this->putGetObjectArrays(new ObjectArrayType(new ComplexObjectType()), $array);
+ }
+
+ public function testPutGetObjectArrayOfBinaryObjects(): void
+ {
+ $array = array();
+ for ($i = 0; $i < 5; $i++) {
+ $binaryObject = new BinaryObject('tstBinaryObj');
+ foreach (TestingHelper::$primitiveValues as $type => $typeInfo) {
+ $fieldName = 'field' . $type;
+ $index = ($i < count($typeInfo['values'])) ? $i : $i % count($typeInfo['values']);
+ $binaryObject->setField($fieldName, $typeInfo['values'][$index], $type);
+ }
+ array_push($array, $binaryObject);
+ }
+ $this->putGetObjectArrays(new ObjectArrayType(), $array);
+ $this->putGetObjectArrays(null, $array);
+ }
+
+ public function testPutGetObjectArrayOfObjectArrays(): void
+ {
+ $complexObjectType = new ComplexObjectType();
+ foreach (TestingHelper::$primitiveValues as $type => $typeInfo) {
+ $complexObjectType->setFieldType('field' . $type, $type);
+ }
+ $array = array();
+ for ($i = 0; $i < 2; $i++) {
+ $innerArray = array();
+ for ($j = 0; $j < 2; $j++) {
+ $object = new TstComplObjectWithPrimitiveFields();
+ foreach (TestingHelper::$primitiveValues as $type => $typeInfo) {
+ $fieldName = 'field' . $type;
+ $index = $i * 10 + $j;
+ $index = ($index < count($typeInfo['values'])) ? $index : $index % count($typeInfo['values']);
+ $object->$fieldName = $typeInfo['values'][$index];
+ }
+ array_push($innerArray, $object);
+ }
+ array_push($array, $innerArray);
+ }
+ $this->putGetObjectArrays(new ObjectArrayType(new ObjectArrayType($complexObjectType)), $array);
+ }
+
+ public function testPutGetObjectArrayOfObjectArraysOfComplexObjectsWithDefaultFieldTypes(): void
+ {
+ $array = array();
+ for ($i = 0; $i < 2; $i++) {
+ $innerArray = array();
+ for ($j = 0; $j < 2; $j++) {
+ $object = new TstComplObjectWithDefaultFieldTypes();
+ foreach (TestingHelper::$primitiveValues as $type => $typeInfo) {
+ if (!array_key_exists('typeOptional', $typeInfo)) {
+ continue;
+ }
+ $fieldName = 'field' . $type;
+ $index = $i * 10 + $j;
+ $index = ($index < count($typeInfo['values'])) ? $index : $index % count($typeInfo['values']);
+ $object->$fieldName = $typeInfo['values'][$index];
+ }
+ array_push($innerArray, $object);
+ }
+ array_push($array, $innerArray);
+ }
+ $this->putGetObjectArrays(new ObjectArrayType(new ObjectArrayType(new ComplexObjectType())), $array);
+ }
+
+ private function putGetObjectArrays(?ObjectArrayType $arrayType, array $value): void
+ {
+ $key = microtime();
+ self::$cache->
+ setKeyType(null)->
+ setValueType($arrayType);
+ try {
+ self::$cache->put($key, $value);
+ $result = self::$cache->get($key);
+ $this->assertTrue(is_array($result));
+ $this->assertTrue(TestingHelper::compare($value, $result));
+ } finally {
+ self::$cache->removeAll();
+ }
+ }
+
+ private function putGetLists(?CollectionObjectType $listType, array $value): void
+ {
+ $key = microtime();
+ self::$cache->
+ setKeyType(null)->
+ setValueType($listType);
+ try {
+ self::$cache->put($key, $value);
+ $result = self::$cache->get($key);
+ $strResult = TestingHelper::printValue($result);
+ $strValue = TestingHelper::printValue($value);
+ $strValueType = TestingHelper::printValue($listType ? $listType->getElementType() : null);
+ $this->assertTrue(
+ is_array($result),
+ "result is not array: result={$strResult}");
+ $this->assertTrue(
+ TestingHelper::compare($value, $result),
+ "Lists are not equal: valueType={$strValueType}, put value={$strValue}, get value={$strResult}");
+ } finally {
+ self::$cache->removeAll();
+ }
+ }
+
+ private function putGetSets(?CollectionObjectType $setType, Set $value): void
+ {
+ $key = microtime();
+ self::$cache->
+ setKeyType(null)->
+ setValueType($setType);
+ try {
+ self::$cache->put($key, $value);
+ $result = self::$cache->get($key);
+ $strResult = TestingHelper::printValue($result);
+ $strValue = TestingHelper::printValue($value);
+ $strValueType = TestingHelper::printValue($setType ? $setType->getElementType() : null);
+ $this->assertTrue(
+ $result instanceof Set,
+ "result is not Set: result={$strResult}");
+ $this->assertTrue(
+ TestingHelper::compare($value, $result),
+ "Sets are not equal: valueType={$strValueType}, put value={$strValue}, get value={$strResult}");
+ } finally {
+ self::$cache->removeAll();
+ }
+ }
+
+ private function putGetArrayMaps(?MapObjectType $mapType, array $value): void
+ {
+ self::$cache->
+ setKeyType(null)->
+ setValueType($mapType);
+ try {
+ $key = microtime();
+ self::$cache->put($key, $value);
+ $result = self::$cache->get($key);
+ $strResult = TestingHelper::printValue($result);
+ $strValue = TestingHelper::printValue($value);
+ $strValueType = TestingHelper::printValue($mapType ? $mapType->getValueType() : null);
+ $this->assertTrue(
+ $result instanceof Map,
+ "result is not Map: result={$strResult}");
+ $this->assertTrue(
+ TestingHelper::compare(new Map($value), $result),
+ "Maps are not equal: valueType={$strValueType}, put value={$strValue}, get value={$strResult}");
+ } finally {
+ self::$cache->removeAll();
+ }
+ }
+
+ private function putGetMaps(?MapObjectType $mapType, Map $value): void
+ {
+ self::$cache->
+ setKeyType(null)->
+ setValueType($mapType);
+ try {
+ $key = microtime();
+ self::$cache->put($key, $value);
+ $result = self::$cache->get($key);
+ $strResult = TestingHelper::printValue($result);
+ $strValue = TestingHelper::printValue($value);
+ $strValueType = TestingHelper::printValue($mapType ? $mapType->getValueType() : null);
+ $this->assertTrue(
+ $result instanceof Map,
+ "result is not Map: result={$strResult}");
+ $this->assertTrue(
+ TestingHelper::compare($value, $result),
+ "Maps are not equal: valueType={$strValueType}, put value={$strValue}, get value={$strResult}");
+ } finally {
+ self::$cache->removeAll();
+ }
+ }
+
+ private function putGetPrimitiveValues(?int $typeCode1, ?int $typeCode2, $value1, $value2): void
+ {
+ self::$cache->
+ setKeyType($typeCode1)->
+ setValueType($typeCode2);
+ try {
+ self::$cache->put($value1, $value2);
+ $result = self::$cache->get($value1);
+ $strValue1 = TestingHelper::printValue($value1);
+ $strValue2 = TestingHelper::printValue($value2);
+ $strResult = TestingHelper::printValue($result);
+ $this->assertTrue(
+ TestingHelper::compare($value2, $result),
+ "values are not equal: keyType={$typeCode1}, key={$strValue1}, valueType={$typeCode2}, put value={$strValue2}, get value={$strResult}");
+ } finally {
+ self::$cache->removeAll();
+ }
+ }
+
+ private function putGetArrays(int $keyType, int $valueType, $key, $value): void
+ {
+ self::$cache->
+ setKeyType($keyType)->
+ setValueType($valueType);
+ try {
+ self::$cache->put($key, $value);
+ $result = self::$cache->get($key);
+ self::$cache->clearKey($key);
+ $strValue = TestingHelper::printValue($value);
+ $strResult = TestingHelper::printValue($result);
+ $this->assertTrue(
+ is_array($result),
+ "result is not Array: arrayType={$valueType}, result={$strResult}");
+ $this->assertTrue(
+ TestingHelper::compare($value, $result),
+ "Arrays are not equal: arrayType={$valueType}, put array={$strValue}, get array={$strResult}");
+ } finally {
+ self::$cache->removeAll();
+ }
+ }
+
+ private static function cleanUp(): void
+ {
+ TestingHelper::destroyCache(self::CACHE_NAME);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/tests/CacheTest.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/CacheTest.php b/modules/platforms/php/tests/CacheTest.php
new file mode 100644
index 0000000..20627cb
--- /dev/null
+++ b/modules/platforms/php/tests/CacheTest.php
@@ -0,0 +1,240 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+use Apache\Ignite\Cache\CacheKeyConfiguration;
+use Apache\Ignite\Cache\QueryField;
+use Apache\Ignite\Cache\QueryEntity;
+use Apache\Ignite\Cache\QueryIndex;
+use PHPUnit\Framework\TestCase;
+use Apache\Ignite\Cache\CacheInterface;
+use Apache\Ignite\Cache\CacheConfiguration;
+use Apache\Ignite\Exception\OperationException;
+use Apache\Ignite\Exception\ClientException;
+
+final class CacheTestCase extends TestCase
+{
+ const CACHE_NAME = '__php_test_cache';
+ const CACHE_NAME2 = '__php_test_cache2';
+ const CACHE_NAME3 = '__php_test_cache3';
+ const CACHE_NAME4 = '__php_test_cache4';
+
+ public static function setUpBeforeClass(): void
+ {
+ TestingHelper::init();
+ self::cleanUp();
+ }
+
+ public static function tearDownAfterClass(): void
+ {
+ self::cleanUp();
+ TestingHelper::cleanUp();
+ }
+
+ public function testCreateCache(): void
+ {
+ $client = TestingHelper::$client;
+ $cache = $client->getCache(self::CACHE_NAME);
+ $this->checkCache($cache, false);
+ $cache = $client->createCache(self::CACHE_NAME);
+ $this->checkCache($cache, true);
+ $cache = $client->getCache(self::CACHE_NAME);
+ $this->checkCache($cache, true);
+ $client->destroyCache(self::CACHE_NAME);
+ }
+
+ public function testCreateCacheTwice(): void
+ {
+ $client = TestingHelper::$client;
+ try {
+ $client->getOrCreateCache(self::CACHE_NAME);
+ $this->expectException(OperationException::class);
+ $client->createCache(self::CACHE_NAME);
+ } finally {
+ $client->destroyCache(self::CACHE_NAME);
+ }
+ }
+
+ public function testGetOrCreateCache(): void
+ {
+ $client = TestingHelper::$client;
+ $cache = $client->getCache(self::CACHE_NAME);
+ $this->checkCache($cache, false);
+ $cache = $client->getOrCreateCache(self::CACHE_NAME);
+ $this->checkCache($cache, true);
+ $cache = $client->getCache(self::CACHE_NAME);
+ $this->checkCache($cache, true);
+ $client->destroyCache(self::CACHE_NAME);
+ }
+
+ public function testGetCacheNames(): void
+ {
+ $client = TestingHelper::$client;
+ $client->getOrCreateCache(self::CACHE_NAME);
+ $client->getOrCreateCache(self::CACHE_NAME2);
+ $cacheNames = $client->cacheNames();
+ $this->assertContains(self::CACHE_NAME, $cacheNames);
+ $this->assertContains(self::CACHE_NAME2, $cacheNames);
+ $client->destroyCache(self::CACHE_NAME);
+ $client->destroyCache(self::CACHE_NAME2);
+ }
+
+ public function testDestroyCache(): void
+ {
+ $client = TestingHelper::$client;
+ $client->getOrCreateCache(self::CACHE_NAME);
+ $client->destroyCache(self::CACHE_NAME);
+
+ $this->expectException(OperationException::class);
+ $client->destroyCache(self::CACHE_NAME);
+ }
+
+ public function testCreateCacheWithConfiguration(): void
+ {
+ $client = TestingHelper::$client;
+ $cacheCfg = (new CacheConfiguration())->
+ setQueryEntities(
+ (new QueryEntity())->
+ setKeyTypeName('INT')->
+ setValueTypeName('Person')->
+ setTableName('Person')->
+ setKeyFieldName('id')->
+ setValueFieldName('salary')->
+ setFields(
+ (new QueryField('id', 'INT'))->setIsKeyField(true),
+ (new QueryField('firstName', 'VARCHAR'))->setIsNotNull(true),
+ (new QueryField('lastName', 'VARCHAR'))->setDefaultValue('lastName'),
+ (new QueryField('salary', 'DOUBLE'))->setPrecision(10)->setScale(10))->
+ setAliases(['id' => 'id', 'firstName' => 'firstName'])->
+ setIndexes(
+ (new QueryIndex('id_idx', QueryIndex::TYPE_SORTED))->
+ setName('id_idx')->
+ setType(QueryIndex::TYPE_SORTED)->
+ setInlineSize(10)->
+ setFields(['id' => true, 'firstName' => false])))->
+ setKeyConfigurations((new CacheKeyConfiguration('Person', 'Person'))->
+ setTypeName('Person')->
+ setAffinityKeyFieldName('Person'));
+
+ $cache = $client->createCache(self::CACHE_NAME3, $cacheCfg);
+ $cfg = $client->getCacheConfiguration(self::CACHE_NAME3);
+ $client->destroyCache(self::CACHE_NAME3);
+ $keyConfig = $cfg->getKeyConfigurations()[0];
+ $queryEntity = $cfg->getQueryEntities()[0];
+ $queryField = $queryEntity->getFields()[0];
+ $queryIndex = $queryEntity->getIndexes()[0];
+ $cfg->
+ setName($cfg->getName())->
+ setAtomicityMode($cfg->getAtomicityMode())->
+ setBackups($cfg->getBackups())->
+ setCacheMode($cfg->getCacheMode())->
+ setCopyOnRead($cfg->getCopyOnRead())->
+ setDataRegionName($cfg->getDataRegionName())->
+ setEagerTtl($cfg->getEagerTtl())->
+ setStatisticsEnabled($cfg->getStatisticsEnabled())->
+ setGroupName($cfg->getGroupName())->
+ setDefaultLockTimeout($cfg->getDefaultLockTimeout())->
+ setMaxConcurrentAsyncOperations($cfg->getMaxConcurrentAsyncOperations())->
+ setMaxQueryIterators($cfg->getMaxQueryIterators())->
+ setIsOnheapCacheEnabled($cfg->getIsOnheapCacheEnabled())->
+ setPartitionLossPolicy($cfg->getPartitionLossPolicy())->
+ setQueryDetailMetricsSize($cfg->getQueryDetailMetricsSize())->
+ setQueryParallelism($cfg->getQueryParallelism())->
+ setReadFromBackup($cfg->getReadFromBackup())->
+ setRebalanceBatchSize($cfg->getRebalanceBatchSize())->
+ setRebalanceBatchesPrefetchCount($cfg->getRebalanceBatchesPrefetchCount())->
+ setRebalanceDelay($cfg->getRebalanceDelay())->
+ setRebalanceMode($cfg->getRebalanceMode())->
+ setRebalanceOrder($cfg->getRebalanceOrder())->
+ setRebalanceThrottle($cfg->getRebalanceThrottle())->
+ setRebalanceTimeout($cfg->getRebalanceTimeout())->
+ setSqlEscapeAll($cfg->getSqlEscapeAll())->
+ setSqlIndexInlineMaxSize($cfg->getSqlIndexInlineMaxSize())->
+ setSqlSchema($cfg->getSqlSchema())->
+ setWriteSynchronizationMode($cfg->getWriteSynchronizationMode())->
+ setKeyConfigurations((new CacheKeyConfiguration())->
+ setTypeName($keyConfig->getTypeName())->
+ setAffinityKeyFieldName($keyConfig->getAffinityKeyFieldName()))->
+ setQueryEntities((new QueryEntity())->
+ setKeyTypeName($queryEntity->getKeyTypeName())->
+ setValueTypeName($queryEntity->getValueTypeName())->
+ setTableName($queryEntity->getTableName())->
+ setKeyFieldName($queryEntity->getKeyFieldName())->
+ setValueFieldName($queryEntity->getValueFieldName())->
+ setFields(
+ (new QueryField())->
+ setName($queryField->getName())->
+ setTypeName($queryField->getTypeName())->
+ setIsKeyField($queryField->getIsKeyField())->
+ setIsNotNull($queryField->getIsNotNull())->
+ setDefaultValue($queryField->getDefaultValue())->
+ setPrecision($queryField->getPrecision())->
+ setScale($queryField->getScale()),
+ $queryEntity->getFields()[1],
+ $queryEntity->getFields()[2],
+ $queryEntity->getFields()[3])->
+ setAliases($queryEntity->getAliases())->
+ setIndexes((new QueryIndex())->
+ setName($queryIndex->getName())->
+ setType($queryIndex->getType())->
+ setInlineSize($queryIndex->getInlineSize())->
+ setFields($queryIndex->getFields())));
+ $cache = $client->getOrCreateCache(self::CACHE_NAME4, $cfg);
+ $cfg2 = $client->getCacheConfiguration(self::CACHE_NAME4);
+ $client->destroyCache(self::CACHE_NAME4);
+ $this->assertTrue(true);
+ }
+
+ public function testCreateCacheWithWrongArgs(): void
+ {
+ $client = TestingHelper::$client;
+ $this->expectException(ClientException::class);
+ $client->createCache('');
+ }
+
+ public function testGetOrCreateCacheWithWrongArgs(): void
+ {
+ $client = TestingHelper::$client;
+ $this->expectException(ClientException::class);
+ $client->getOrCreateCache('');
+ }
+
+ public function testGetCacheWithWrongArgs(): void
+ {
+ $client = TestingHelper::$client;
+ $this->expectException(ClientException::class);
+ $client->getCache('');
+ }
+
+ private function checkCache(CacheInterface $cache, bool $cacheExists): void
+ {
+ if (!$cacheExists) {
+ $this->expectException(OperationException::class);
+ }
+ $cache->put(0, 0);
+ }
+
+ private static function cleanUp(): void
+ {
+ TestingHelper::destroyCache(self::CACHE_NAME);
+ TestingHelper::destroyCache(self::CACHE_NAME2);
+ TestingHelper::destroyCache(self::CACHE_NAME3);
+ TestingHelper::destroyCache(self::CACHE_NAME4);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/tests/ComplexObjectTest.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/ComplexObjectTest.php b/modules/platforms/php/tests/ComplexObjectTest.php
new file mode 100644
index 0000000..430c068
--- /dev/null
+++ b/modules/platforms/php/tests/ComplexObjectTest.php
@@ -0,0 +1,428 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+use Ds\Map;
+use PHPUnit\Framework\TestCase;
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Type\MapObjectType;
+use Apache\Ignite\Type\ComplexObjectType;
+use Apache\Ignite\Data\BinaryObject;
+
+class Class1
+{
+ public $field_1_1;
+ public $field_1_2;
+ public $field_1_3;
+
+ public function __construct()
+ {
+ $this->field_1_1 = null;
+ $this->field_1_2 = new Class2();
+ $this->field_1_3 = null;
+ }
+}
+
+class SubClass1 extends Class1
+{
+ public $field_1_4;
+ public $field_1_5;
+ public $field_1_6;
+ public $field_1_7;
+ public $field_1_8;
+
+ public function __construct()
+ {
+ parent::__construct();
+ $this->field_1_4 = null;
+ $this->field_1_5 = new Class3();
+ $this->field_1_6 = null;
+ $this->field_1_7 = null;
+ $this->field_1_8 = null;
+ }
+}
+
+class Class2
+{
+ public $field_2_1;
+ public $field_2_2;
+}
+
+class Class3 {
+ public $field_3_1;
+ public $field_3_2;
+}
+
+final class ComplexObjectTestCase extends TestCase
+{
+ const CACHE_NAME = '__php_test_compl_obj_cache';
+
+ private static $cache;
+
+ public static function setUpBeforeClass(): void
+ {
+ TestingHelper::init();
+ self::cleanUp();
+ self::$cache = TestingHelper::$client->getOrCreateCache(self::CACHE_NAME);
+ }
+
+ public static function tearDownAfterClass(): void
+ {
+ self::cleanUp();
+ TestingHelper::cleanUp();
+ }
+
+ public function testPutGetComplexObjects(): void
+ {
+ $value1 = new Class1();
+ $value1->field_1_1 = $this->getPrimitiveValue(ObjectType::BYTE);
+ $value1->field_1_2->field_2_1 = $this->getPrimitiveValue(ObjectType::SHORT);
+ $value1->field_1_2->field_2_2 = $this->getPrimitiveValue(ObjectType::INTEGER);
+ $value1->field_1_3 = $this->getPrimitiveValue(ObjectType::LONG);
+
+ $valueType1 = (new ComplexObjectType())->
+ setFieldType('field_1_1', ObjectType::BYTE)->
+ setFieldType('field_1_2', (new ComplexObjectType())->
+ setIgniteTypeName('Class2ShortInteger')->
+ setPhpClassName(Class2::class)->
+ setFieldType('field_2_1', ObjectType::SHORT)->
+ setFieldType('field_2_2', ObjectType::INTEGER))->
+ setFieldType('field_1_3', ObjectType::LONG);
+
+ $value2 = new SubClass1();
+ $value2->field_1_1 = $this->getPrimitiveValue(ObjectType::FLOAT);
+ $value2->field_1_2->field_2_1 = $this->getPrimitiveValue(ObjectType::DOUBLE);
+ $value2->field_1_2->field_2_2 = $this->getPrimitiveValue(ObjectType::CHAR);
+ $value2->field_1_3 = $this->getPrimitiveValue(ObjectType::BOOLEAN);
+ $value2->field_1_4 = $this->getPrimitiveValue(ObjectType::STRING);
+ $value2->field_1_5->field_3_1 = $this->getPrimitiveValue(ObjectType::DATE);
+ $value2->field_1_5->field_3_2 = $this->getPrimitiveValue(ObjectType::UUID);
+ $value2->field_1_6 = $this->getPrimitiveValue(ObjectType::DECIMAL);
+ $value2->field_1_7 = $this->getPrimitiveValue(ObjectType::TIMESTAMP);
+ $value2->field_1_8 = $this->getPrimitiveValue(ObjectType::TIME);
+
+ $valueType2 = (new ComplexObjectType())->
+ setFieldType('field_1_1', ObjectType::FLOAT)->
+ setFieldType('field_1_2', (new ComplexObjectType())->
+ setIgniteTypeName('Class2DoubleChar')->
+ setPhpClassName(Class2::class)->
+ setFieldType('field_2_1', ObjectType::DOUBLE)->
+ setFieldType('field_2_2', ObjectType::CHAR))->
+ setFieldType('field_1_3', ObjectType::BOOLEAN)->
+ setFieldType('field_1_4', ObjectType::STRING)->
+ setFieldType('field_1_5', (new ComplexObjectType())->
+ setFieldType('field_3_1', ObjectType::DATE)->
+ setFieldType('field_3_2', ObjectType::UUID))->
+ setFieldType('field_1_6', ObjectType::DECIMAL)->
+ setFieldType('field_1_7', ObjectType::TIMESTAMP)->
+ setFieldType('field_1_8', ObjectType::TIME);
+
+ $this->putGetComplexObjectsWithDifferentTypes(
+ $value1, $value2, $valueType1, $valueType2, Class1::class, SubClass1::class);
+ }
+
+ public function testPutGetComplexObjectsWithArrays(): void
+ {
+ $value1 = new Class1();
+ $value1->field_1_1 = $this->getArrayValues(ObjectType::BYTE_ARRAY);
+ $value1->field_1_2->field_2_1 = $this->getArrayValues(ObjectType::SHORT_ARRAY);
+ $value1->field_1_2->field_2_2 = $this->getArrayValues(ObjectType::INTEGER_ARRAY);
+ $value1->field_1_3 = $this->getArrayValues(ObjectType::LONG_ARRAY);
+
+ $valueType1 = (new ComplexObjectType())->
+ setIgniteTypeName('Class1WithArrays')->
+ setPhpClassName(Class1::class)->
+ setFieldType('field_1_1', ObjectType::BYTE_ARRAY)->
+ setFieldType('field_1_2', (new ComplexObjectType())->
+ setIgniteTypeName('Class2WithShortIntegerArrays')->
+ setPhpClassName(Class2::class)->
+ setFieldType('field_2_1', ObjectType::SHORT_ARRAY)->
+ setFieldType('field_2_2', ObjectType::INTEGER_ARRAY))->
+ setFieldType('field_1_3', ObjectType::LONG_ARRAY);
+
+ $value2 = new SubClass1();
+ $value2->field_1_1 = $this->getArrayValues(ObjectType::FLOAT_ARRAY);
+ $value2->field_1_2->field_2_1 = $this->getArrayValues(ObjectType::DOUBLE_ARRAY);
+ $value2->field_1_2->field_2_2 = $this->getArrayValues(ObjectType::CHAR_ARRAY);
+ $value2->field_1_3 = $this->getArrayValues(ObjectType::BOOLEAN_ARRAY);
+ $value2->field_1_4 = $this->getArrayValues(ObjectType::STRING_ARRAY);
+ $value2->field_1_5->field_3_1 = $this->getArrayValues(ObjectType::DATE_ARRAY);
+ $value2->field_1_5->field_3_2 = $this->getArrayValues(ObjectType::UUID_ARRAY);
+ $value2->field_1_6 = $this->getArrayValues(ObjectType::DECIMAL_ARRAY);
+ $value2->field_1_7 = $this->getArrayValues(ObjectType::TIMESTAMP_ARRAY);
+ $value2->field_1_8 = $this->getArrayValues(ObjectType::TIME_ARRAY);
+
+ $valueType2 = (new ComplexObjectType())->
+ setIgniteTypeName('SubClass1WithArrays')->
+ setPhpClassName(SubClass1::class)->
+ setFieldType('field_1_1', ObjectType::FLOAT_ARRAY)->
+ setFieldType('field_1_2', (new ComplexObjectType())->
+ setIgniteTypeName('Class2WithDoubleCharArrays')->
+ setPhpClassName(Class2::class)->
+ setFieldType('field_2_1', ObjectType::DOUBLE_ARRAY)->
+ setFieldType('field_2_2', ObjectType::CHAR_ARRAY))->
+ setFieldType('field_1_3', ObjectType::BOOLEAN_ARRAY)->
+ setFieldType('field_1_4', ObjectType::STRING_ARRAY)->
+ setFieldType('field_1_5', (new ComplexObjectType())->
+ setIgniteTypeName('Class3WithArrays')->
+ setPhpClassName(Class3::class)->
+ setFieldType('field_3_1', ObjectType::DATE_ARRAY)->
+ setFieldType('field_3_2', ObjectType::UUID_ARRAY))->
+ setFieldType('field_1_6', ObjectType::DECIMAL_ARRAY)->
+ setFieldType('field_1_7', ObjectType::TIMESTAMP_ARRAY)->
+ setFieldType('field_1_8', ObjectType::TIME_ARRAY);
+
+ $this->putGetComplexObjectsWithDifferentTypes(
+ $value1, $value2, $valueType1, $valueType2, Class1::class, SubClass1::class, true);
+ }
+
+ public function testPutGetComplexObjectsWithMaps(): void
+ {
+ $value1 = new Class1();
+ $value1->field_1_1 = $this->getMapValue(ObjectType::BYTE);
+ $value1->field_1_2->field_2_1 = $this->getMapValue(ObjectType::SHORT);
+ $value1->field_1_2->field_2_2 = $this->getMapValue(ObjectType::INTEGER);
+ $value1->field_1_3 = $this->getMapValue(ObjectType::LONG);
+
+ $valueType1 = (new ComplexObjectType())->
+ setIgniteTypeName('Class1WithMaps')->
+ setPhpClassName(Class1::class)->
+ setFieldType('field_1_1', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::BYTE, ObjectType::BYTE))->
+ setFieldType('field_1_2', (new ComplexObjectType())->
+ setIgniteTypeName('Class2WithShortIntegerMaps')->
+ setPhpClassName(Class2::class)->
+ setFieldType('field_2_1', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::SHORT, ObjectType::SHORT))->
+ setFieldType('field_2_2', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::INTEGER, ObjectType::INTEGER)))->
+ setFieldType('field_1_3', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::STRING, ObjectType::LONG));
+
+ $value2 = new SubClass1();
+ $value2->field_1_1 = $this->getMapValue(ObjectType::FLOAT);
+ $value2->field_1_2->field_2_1 = $this->getMapValue(ObjectType::DOUBLE);
+ $value2->field_1_2->field_2_2 = $this->getMapValue(ObjectType::CHAR);
+ $value2->field_1_3 = $this->getMapValue(ObjectType::BOOLEAN);
+ $value2->field_1_4 = $this->getMapValue(ObjectType::STRING);
+ $value2->field_1_5->field_3_1 = $this->getMapValue(ObjectType::DATE);
+ $value2->field_1_5->field_3_2 = $this->getMapValue(ObjectType::UUID);
+ $value2->field_1_6 = $this->getMapValue(ObjectType::DECIMAL);
+ $value2->field_1_7 = $this->getMapValue(ObjectType::TIMESTAMP);
+ $value2->field_1_8 = $this->getMapValue(ObjectType::TIME);
+
+ $valueType2 = (new ComplexObjectType())->
+ setIgniteTypeName('SubClass1WithArrays')->
+ setPhpClassName(SubClass1::class)->
+ setFieldType('field_1_1', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::STRING, ObjectType::FLOAT))->
+ setFieldType('field_1_2', (new ComplexObjectType())->
+ setIgniteTypeName('Class2WithDoubleCharArrays')->
+ setPhpClassName(Class2::class)->
+ setFieldType('field_2_1', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::STRING, ObjectType::DOUBLE))->
+ setFieldType('field_2_2', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::CHAR, ObjectType::CHAR)))->
+ setFieldType('field_1_3', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::BOOLEAN, ObjectType::BOOLEAN))->
+ setFieldType('field_1_4', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::STRING, ObjectType::STRING))->
+ setFieldType('field_1_5', (new ComplexObjectType())->
+ setIgniteTypeName('Class3WithArrays')->
+ setPhpClassName(Class3::class)->
+ setFieldType('field_3_1', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::STRING, ObjectType::DATE))->
+ setFieldType('field_3_2', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::STRING, ObjectType::UUID)))->
+ setFieldType('field_1_6', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::STRING, ObjectType::DECIMAL))->
+ setFieldType('field_1_7', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::STRING, ObjectType::TIMESTAMP))->
+ setFieldType('field_1_8', new MapObjectType(MapObjectType::HASH_MAP, ObjectType::STRING, ObjectType::TIME));
+
+ $this->putGetComplexObjectsWithMaps(
+ $value1, $value2, $valueType1, $valueType2, Class1::class, SubClass1::class);
+ }
+
+ public function testPutGetBinaryObjectsFromObjects(): void
+ {
+ $valueType = (new ComplexObjectType())->
+ setIgniteTypeName('Class1WithStringObjStringArray')->
+ setPhpClassName(Class1::class)->
+ setFieldType('field_1_1', ObjectType::STRING)->
+ setFieldType('field_1_2', (new ComplexObjectType())->
+ setIgniteTypeName('Class2WithShortBoolean')->
+ setPhpClassName(Class2::class)->
+ setFieldType('field_2_1', ObjectType::SHORT)->
+ setFieldType('field_2_2', ObjectType::BOOLEAN))->
+ setFieldType('field_1_3', ObjectType::STRING_ARRAY);
+ $this->putGetBinaryObjects($valueType);
+ $defaultValueType = (new ComplexObjectType())->
+ setIgniteTypeName('Class1Default')->
+ setPhpClassName(Class1::class)->
+ setFieldType('field_1_2', (new ComplexObjectType())->
+ setIgniteTypeName('Class2Default')->
+ setPhpClassName(Class2::class));
+ $this->putGetBinaryObjects($defaultValueType);
+ }
+
+ private function putGetComplexObjectsWithDifferentTypes(
+ $key, $value, $keyType, $valueType, $keyClass, $valueClass, $isNullable = false)
+ {
+ $this->putGetComplexObjects($key, $value, $keyType, $valueType, $value);
+
+ $binaryKey = BinaryObject::fromObject($key, $keyType);
+ $binaryValue = BinaryObject::fromObject($value, $valueType);
+ $this->putGetComplexObjects($binaryKey, $binaryValue, null, null, $value);
+
+ if ($isNullable) {
+ $this->putGetComplexObjects(new $keyClass(), new $valueClass(), $keyType, $valueType, new $valueClass());
+ }
+
+ if ($isNullable) {
+ $binaryKey = BinaryObject::fromObject(new $keyClass(), $keyType);
+ $binaryValue = BinaryObject::fromObject(new $valueClass(), $valueType);
+ $this->putGetComplexObjects($binaryKey, $binaryValue, null, null, new $valueClass());
+ }
+ }
+
+ private function putGetComplexObjectsWithMaps(
+ $key, $value, $keyType, $valueType, $keyClass, $valueClass)
+ {
+ $this->putGetComplexObjects($key, $value, $keyType, $valueType, $value);
+
+ $this->putGetComplexObjects(new $keyClass(), new $valueClass(), $keyType, $valueType, new $valueClass());
+ }
+
+ private function putGetComplexObjects($key, $value, $keyType, $valueType, $valuePattern)
+ {
+ self::$cache->
+ setKeyType($keyType)->
+ setValueType($valueType);
+ try {
+ self::$cache->put($key, $value);
+ $result = self::$cache->get($key);
+ $strResult = TestingHelper::printValue($result);
+ $strValue = TestingHelper::printValue($valuePattern);
+ $this->assertTrue(
+ TestingHelper::compare($valuePattern, $result),
+ "values are not equal: put value={$strValue}, get value={$strResult}");
+ } finally {
+ self::$cache->removeAll();
+ }
+ }
+
+ private function putGetBinaryObjects($valueType): void
+ {
+ $value1 = new Class1();
+ $value1->field_1_1 = 'abc';
+ $value1->field_1_2->field_2_1 = 1234;
+ $value1->field_1_2->field_2_2 = true;
+ $value1->field_1_3 = ['a', 'bb', 'ccc'];
+
+ $value2 = new Class1();
+ $value2->field_1_1 = 'def';
+ $value2->field_1_2->field_2_1 = 5432;
+ $value2->field_1_2->field_2_2 = false;
+ $value2->field_1_3 = ['a', 'bb', 'ccc', 'dddd'];
+
+ $value3 = new Class1();
+ $value3->field_1_1 = 'defdef';
+ $value3->field_1_2->field_2_1 = 543;
+ $value3->field_1_2->field_2_2 = false;
+ $value3->field_1_3 = ['a', 'bb', 'ccc', 'dddd', 'eeeee'];
+
+ $field_1_2_Type = $valueType ? $valueType->getFieldType('field_1_2') : null;
+
+ $binaryValue1 = BinaryObject::fromObject($value1, $valueType);
+ $binaryValue2 = BinaryObject::fromObject($value2, $valueType);
+ $binaryValue3 = BinaryObject::fromObject($value3, $valueType);
+
+ self::$cache->
+ setKeyType(null)->
+ setValueType(null);
+ $cache = self::$cache;
+ try {
+ $cache->put($binaryValue1, $binaryValue2);
+ $result = $cache->get($binaryValue1);
+ $this->binaryObjectEquals($result, $value2, $valueType);
+
+ $binaryValue1->setField('field_1_1', 'abcde');
+ $result = $cache->get($binaryValue1);
+ $this->assertTrue($result === null);
+
+ $binaryValue2->setField('field_1_1', $value3->field_1_1);
+ $binaryValue2->setField('field_1_2', $value3->field_1_2, $field_1_2_Type);
+ $binaryValue2->setField('field_1_3', $value3->field_1_3);
+ $cache->put($binaryValue1, $binaryValue2);
+ $result = $cache->get($binaryValue1);
+ $this->binaryObjectEquals($result, $value3, $valueType);
+
+ $binaryValue1->setField('field_1_1', 'abc');
+ $binaryValue1->setField('field_1_3', $binaryValue1->getField('field_1_3'));
+ $result = $cache->get($binaryValue1);
+ $this->binaryObjectEquals($result, $value2, $valueType);
+
+ $result = $cache->get($binaryValue1);
+ $this->binaryObjectEquals($result, $value2, $valueType);
+
+ $binaryValue3->setField('field_1_1', $result->getField('field_1_1'));
+ $binaryValue3->setField('field_1_2', $result->getField('field_1_2', $field_1_2_Type), $field_1_2_Type);
+ $binaryValue3->setField('field_1_3', $result->getField('field_1_3'));
+ $cache->put($binaryValue1, $binaryValue3);
+ $result = $cache->get($binaryValue1);
+ $this->binaryObjectEquals($result, $value2, $valueType);
+ } finally {
+ self::$cache->removeAll();
+ }
+ }
+
+ private function binaryObjectEquals(BinaryObject $binaryObj, $valuePattern, $valueType): void
+ {
+ $strBinObj = TestingHelper::printValue($binaryObj);
+ $strValue = TestingHelper::printValue($valuePattern);
+ $this->assertTrue(
+ TestingHelper::compare($valuePattern, $binaryObj),
+ "binary values are not equal: put value={$strValue}, get value={$strBinObj}");
+ if ($valueType) {
+ $object = $binaryObj->toObject($valueType);
+ $strObject = TestingHelper::printValue($object);
+ $this->assertTrue(
+ TestingHelper::compare($valuePattern, $object),
+ "values are not equal: put value={$strValue}, get value={$strObject}");
+ }
+ }
+
+ private function getPrimitiveValue(int $typeCode)
+ {
+ return TestingHelper::$primitiveValues[$typeCode]['values'][0];
+ }
+
+ private function getArrayValues(int $typeCode)
+ {
+ return TestingHelper::$primitiveValues[TestingHelper::$arrayValues[$typeCode]['elemType']]['values'];
+ }
+
+ private function getMapValue(int $typeCode)
+ {
+ $map = new Map();
+ $values = TestingHelper::$primitiveValues[$typeCode]['values'];
+ $length = count($values);
+ for ($i = 0; $i < $length; $i++) {
+ $value = $values[$i];
+ if (!TestingHelper::$primitiveValues[$typeCode]['isMapKey']) {
+ $value = print_r($value, true);
+ }
+ $map->put($value, $values[$length - $i - 1]);
+ }
+ return $map;
+ }
+
+ private static function cleanUp(): void
+ {
+ TestingHelper::destroyCache(self::CACHE_NAME);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/tests/ScanQueryTest.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/ScanQueryTest.php b/modules/platforms/php/tests/ScanQueryTest.php
new file mode 100644
index 0000000..07b9f61
--- /dev/null
+++ b/modules/platforms/php/tests/ScanQueryTest.php
@@ -0,0 +1,167 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+use Ds\Set;
+use PHPUnit\Framework\TestCase;
+use Apache\Ignite\Query\ScanQuery;
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Cache\CacheEntry;
+
+final class ScanQueryTestCase extends TestCase
+{
+ const CACHE_NAME = '__php_test_cache_scan_query';
+ const CACHE_NAME2 = '__php_test_cache_scan_query_2';
+ const ELEMENTS_NUMBER = 10;
+
+ private static $cache;
+
+ public static function setUpBeforeClass(): void
+ {
+ TestingHelper::init();
+ self::cleanUp();
+ self::$cache = TestingHelper::$client->getOrCreateCache(self::CACHE_NAME);
+ self::generateData();
+ }
+
+ public static function tearDownAfterClass(): void
+ {
+ self::cleanUp();
+ TestingHelper::cleanUp();
+ }
+
+ public function testGetAll(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query(new ScanQuery());
+ $set = new Set();
+ foreach ($cursor->getAll() as $cacheEntry) {
+ $this->checkCursorResult($cacheEntry);
+ $set->add($cacheEntry->getKey());
+ }
+ $this->assertEquals($set->count(), self::ELEMENTS_NUMBER);
+ }
+
+ public function testGetAllWithPageSize(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query((new ScanQuery())->setPageSize(1));
+ $set = new Set();
+ foreach ($cursor->getAll() as $cacheEntry) {
+ $this->checkCursorResult($cacheEntry);
+ $set->add($cacheEntry->getKey());
+ }
+ $this->assertEquals($set->count(), self::ELEMENTS_NUMBER);
+ }
+
+ public function testIterateCursor(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query(new ScanQuery());
+ $set = new Set();
+ foreach ($cursor as $cacheEntry) {
+ $this->checkCursorResult($cacheEntry);
+ $set->add($cacheEntry->getKey());
+ }
+ $this->assertEquals($set->count(), self::ELEMENTS_NUMBER);
+ }
+
+ public function testIterateCursorWithPageSize(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query((new ScanQuery())->setPageSize(2));
+ $set = new Set();
+ foreach ($cursor as $cacheEntry) {
+ $this->checkCursorResult($cacheEntry);
+ $set->add($cacheEntry->getKey());
+ }
+ $this->assertEquals($set->count(), self::ELEMENTS_NUMBER);
+ }
+
+ public function testCloseCursor(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query((new ScanQuery())->setPageSize(1));
+ $cursor->rewind();
+ $this->assertTrue($cursor->valid());
+ $this->checkCursorResult($cursor->current());
+ $cursor->next();
+ $cursor->close();
+ }
+
+ public function testCloseCursorAfterGetAll(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query((new ScanQuery())->setPageSize(1));
+ $cursor->getAll();
+ $cursor->close();
+ $this->assertTrue(true);
+ }
+
+ public function testScanQuerySettings(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query((new ScanQuery())->
+ setPartitionNumber(0)->
+ setPageSize(2)->
+ setLocal(true));
+ $cursor->getAll();
+ $this->assertTrue(true);
+ }
+
+ public function testScanEmptyCache(): void
+ {
+ $cache = TestingHelper::$client->getOrCreateCache(self::CACHE_NAME2);
+ $cache->removeAll();
+ $cursor = $cache->query(new ScanQuery());
+ $cacheEntries = $cursor->getAll();
+ $this->assertEquals(count($cacheEntries), 0);
+
+ $cursor = $cache->query(new ScanQuery());
+ foreach ($cursor as $entry) {
+ $this->assertTrue(false);
+ }
+ $cursor->close();
+ }
+
+ private function checkCursorResult(CacheEntry $cacheEntry): void
+ {
+ $this->assertEquals($cacheEntry->getValue(), self::generateValue($cacheEntry->getKey()));
+ $this->assertTrue($cacheEntry->getKey() >= 0 && $cacheEntry->getKey() < self::ELEMENTS_NUMBER);
+ }
+
+ private static function generateData(): void
+ {
+ $cache = self::$cache;
+ $cache->setKeyType(ObjectType::INTEGER);
+ for ($i = 0; $i < self::ELEMENTS_NUMBER; $i++) {
+ $cache->put($i, self::generateValue($i));
+ }
+ }
+
+ private static function generateValue(int $key): string
+ {
+ return 'value' . $key;
+ }
+
+ private static function cleanUp(): void
+ {
+ TestingHelper::destroyCache(self::CACHE_NAME);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/tests/SqlFieldsQueryTest.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/SqlFieldsQueryTest.php b/modules/platforms/php/tests/SqlFieldsQueryTest.php
new file mode 100644
index 0000000..3e74ca0
--- /dev/null
+++ b/modules/platforms/php/tests/SqlFieldsQueryTest.php
@@ -0,0 +1,200 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+use Ds\Set;
+use Apache\Ignite\Cache\CacheConfiguration;
+use Apache\Ignite\Query\SqlFieldsQuery;
+use PHPUnit\Framework\TestCase;
+use Apache\Ignite\Type\ObjectType;
+
+final class SqlFieldsQueryTestCase extends TestCase
+{
+ const CACHE_NAME = '__php_test_sql_fields_query';
+ const ELEMENTS_NUMBER = 10;
+ const TABLE_NAME = '__php_test_SqlFieldsQuery_table';
+
+ private static $cache;
+ private static $selectFromTable;
+
+ public static function setUpBeforeClass(): void
+ {
+ TestingHelper::init();
+ self::cleanUp();
+ self::$cache = TestingHelper::$client->getOrCreateCache(
+ self::CACHE_NAME,
+ (new CacheConfiguration())->setSqlSchema('PUBLIC'));
+ self::generateData();
+ $tableName = self::TABLE_NAME;
+ self::$selectFromTable = "SELECT * FROM {$tableName}";
+ }
+
+ public static function tearDownAfterClass(): void
+ {
+ self::dropTables();
+ self::cleanUp();
+ TestingHelper::cleanUp();
+ }
+
+ public function testGetAll(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query(new SqlFieldsQuery(self::$selectFromTable));
+ $set = new Set();
+ foreach ($cursor->getAll() as $fields) {
+ $this->checkCursorResult($fields);
+ $set->add($fields[0]);
+ }
+ $this->assertEquals($set->count(), self::ELEMENTS_NUMBER);
+ }
+
+ public function testGetAllWithPageSize(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query((new SqlFieldsQuery(self::$selectFromTable))->setPageSize(1));
+ $set = new Set();
+ foreach ($cursor->getAll() as $fields) {
+ $this->checkCursorResult($fields);
+ $set->add($fields[0]);
+ }
+ $this->assertEquals($set->count(), self::ELEMENTS_NUMBER);
+ }
+
+ public function testIterateCursor(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query(new SqlFieldsQuery(self::$selectFromTable));
+ $set = new Set();
+ foreach ($cursor as $fields) {
+ $this->checkCursorResult($fields);
+ $set->add($fields[0]);
+ }
+ $this->assertEquals($set->count(), self::ELEMENTS_NUMBER);
+ }
+
+ public function testIterateCursorWithPageSize(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query((new SqlFieldsQuery(self::$selectFromTable))->setPageSize(2));
+ $set = new Set();
+ foreach ($cursor as $fields) {
+ $this->checkCursorResult($fields);
+ $set->add($fields[0]);
+ }
+ $this->assertEquals($set->count(), self::ELEMENTS_NUMBER);
+ }
+
+ public function testCloseCursor(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query((new SqlFieldsQuery(self::$selectFromTable))->setPageSize(1));
+ $cursor->rewind();
+ $this->assertTrue($cursor->valid());
+ $this->checkCursorResult($cursor->current());
+ $cursor->next();
+ $cursor->close();
+ }
+
+ public function testCloseCursorAfterGetAll(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query(new SqlFieldsQuery(self::$selectFromTable));
+ $cursor->getAll();
+ $cursor->close();
+ $this->assertTrue(true);
+ }
+
+ public function testSqlFieldsQuerySettings(): void
+ {
+ $tableName = self::TABLE_NAME;
+ $cache = self::$cache;
+ $cursor = $cache->query((new SqlFieldsQuery(self::$selectFromTable))->
+ setPageSize(2)->
+ setLocal(false)->
+ setSql("INSERT INTO {$tableName} (field1, field2) VALUES (?, ?)")->
+ setArgTypes(ObjectType::INTEGER, ObjectType::STRING)->
+ setArgs(50, 'test')->
+ setDistributedJoins(true)->
+ setReplicatedOnly(false)->
+ setTimeout(10000)->
+ setSchema('PUBLIC')->
+ setMaxRows(20)->
+ setStatementType(SqlFieldsQuery::STATEMENT_TYPE_ANY)->
+ setEnforceJoinOrder(true)->
+ setCollocated(false)->
+ setLazy(true)->
+ setIncludeFieldNames(true));
+ $cursor->getAll();
+ $this->assertTrue(true);
+ }
+
+ public function testGetEmptyResults(): void
+ {
+ $tableName = self::TABLE_NAME;
+ $cache = self::$cache;
+ $cursor = $cache->query(new SqlFieldsQuery("SELECT * FROM {$tableName} WHERE field1 > 100"));
+ $entries = $cursor->getAll();
+ $this->assertEquals(count($entries), 0);
+ $cursor->close();
+
+ $cursor = $cache->query(new SqlFieldsQuery("SELECT * FROM {$tableName} WHERE field1 > 100"));
+ foreach ($cursor as $fields) {
+ $this->assertTrue(false);
+ }
+ $cursor->close();
+ }
+
+ private function checkCursorResult(array $fields): void
+ {
+ $this->assertEquals(count($fields), 2);
+ $this->assertEquals($fields[1], self::generateValue($fields[0]));
+ $this->assertTrue($fields[0] >= 0 && $fields[0] < self::ELEMENTS_NUMBER);
+ }
+
+ private static function dropTables(): void
+ {
+ $tableName = self::TABLE_NAME;
+ self::$cache->query(new SqlFieldsQuery("DROP TABLE {$tableName}"))->getAll();
+ }
+
+ private static function generateData(): void
+ {
+ $tableName = self::TABLE_NAME;
+ $cache = self::$cache;
+ $cache->query(new SqlFieldsQuery(
+ "CREATE TABLE IF NOT EXISTS {$tableName} (field1 INT, field2 VARCHAR, PRIMARY KEY (field1))"
+ ))->getAll();
+ $insertQuery = (new SqlFieldsQuery("INSERT INTO {$tableName} (field1, field2) VALUES (?, ?)"))->
+ setArgTypes(ObjectType::INTEGER);
+
+ for ($i = 0; $i < self::ELEMENTS_NUMBER; $i++) {
+ $cache->query($insertQuery->setArgs($i, self::generateValue($i)))->getAll();
+ }
+ }
+
+ private static function generateValue(int $key): string
+ {
+ return 'value' . $key;
+ }
+
+ private static function cleanUp(): void
+ {
+ TestingHelper::destroyCache(self::CACHE_NAME);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/tests/SqlQueryTest.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/SqlQueryTest.php b/modules/platforms/php/tests/SqlQueryTest.php
new file mode 100644
index 0000000..7c272c7
--- /dev/null
+++ b/modules/platforms/php/tests/SqlQueryTest.php
@@ -0,0 +1,204 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+use Ds\Set;
+use PHPUnit\Framework\TestCase;
+use Apache\Ignite\Cache\CacheEntry;
+use Apache\Ignite\Cache\QueryEntity;
+use Apache\Ignite\Cache\QueryField;
+use Apache\Ignite\Cache\CacheConfiguration;
+use Apache\Ignite\Query\SqlQuery;
+use Apache\Ignite\Query\SqlFieldsQuery;
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Type\ComplexObjectType;
+
+class SqlQueryTestClass
+{
+ public $field1;
+ public $field2;
+}
+
+final class SqlQueryTestCase extends TestCase
+{
+ const CACHE_NAME = '__php_test_sql_query';
+ const ELEMENTS_NUMBER = 10;
+ const TABLE_NAME = '__php_test_SqlQuery_table';
+
+ private static $cache;
+ private static $selectFromTable;
+
+ public static function setUpBeforeClass(): void
+ {
+ TestingHelper::init();
+ self::cleanUp();
+ self::$cache = (TestingHelper::$client->getOrCreateCache(
+ self::CACHE_NAME,
+ (new CacheConfiguration())->
+ setQueryEntities((new QueryEntity())->
+ setKeyTypeName('java.lang.Integer')->
+ setValueTypeName(self::TABLE_NAME)->
+ setFields(
+ new QueryField('field1', 'java.lang.Integer'),
+ new QueryField('field2', 'java.lang.String')))))->
+ setKeyType(ObjectType::INTEGER)->
+ setValueType((new ComplexObjectType())->
+ setIgniteTypeName(self::TABLE_NAME)->
+ setPhpClassName(SqlQueryTestClass::class)->
+ setFieldType('field1', ObjectType::INTEGER));
+ self::generateData();
+ $tableName = self::TABLE_NAME;
+ self::$selectFromTable = "SELECT * FROM {$tableName}";
+ }
+
+ public static function tearDownAfterClass(): void
+ {
+ self::cleanUp();
+ TestingHelper::cleanUp();
+ }
+
+ public function testGetAll(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query((new SqlQuery(self::TABLE_NAME, self::$selectFromTable)));
+ $set = new Set();
+ foreach ($cursor->getAll() as $cacheEntry) {
+ $this->checkCursorResult($cacheEntry);
+ $set->add($cacheEntry->getKey());
+ }
+ $this->assertEquals($set->count(), self::ELEMENTS_NUMBER);
+ }
+
+ public function testGetAllWithPageSize(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query((new SqlQuery(self::TABLE_NAME, self::$selectFromTable))->setPageSize(1));
+ $set = new Set();
+ foreach ($cursor->getAll() as $cacheEntry) {
+ $this->checkCursorResult($cacheEntry);
+ $set->add($cacheEntry->getKey());
+ }
+ $this->assertEquals($set->count(), self::ELEMENTS_NUMBER);
+ }
+
+ public function testIterateCursor(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query(new SqlQuery(self::TABLE_NAME, self::$selectFromTable));
+ $set = new Set();
+ foreach ($cursor as $cacheEntry) {
+ $this->checkCursorResult($cacheEntry);
+ $set->add($cacheEntry->getKey());
+ }
+ $this->assertEquals($set->count(), self::ELEMENTS_NUMBER);
+ }
+
+ public function testIterateCursorWithPageSize(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query((new SqlQuery(self::TABLE_NAME, self::$selectFromTable))->setPageSize(2));
+ $set = new Set();
+ foreach ($cursor as $cacheEntry) {
+ $this->checkCursorResult($cacheEntry);
+ $set->add($cacheEntry->getKey());
+ }
+ $this->assertEquals($set->count(), self::ELEMENTS_NUMBER);
+ }
+
+ public function testCloseCursor(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query((new SqlQuery(self::TABLE_NAME, self::$selectFromTable))->setPageSize(1));
+ $cursor->rewind();
+ $this->assertTrue($cursor->valid());
+ $this->checkCursorResult($cursor->current());
+ $cursor->next();
+ $cursor->close();
+ }
+
+ public function testCloseCursorAfterGetAll(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query(new SqlQuery(self::TABLE_NAME, self::$selectFromTable));
+ $cursor->getAll();
+ $cursor->close();
+ $this->assertTrue(true);
+ }
+
+ public function testSqlQuerySettings(): void
+ {
+ $cache = self::$cache;
+ $cursor = $cache->query((new SqlQuery(self::TABLE_NAME, self::$selectFromTable))->
+ setType(self::TABLE_NAME)->
+ setPageSize(2)->
+ setLocal(false)->
+ setSql('field1 > ? and field1 <= ?')->
+ setArgTypes(ObjectType::INTEGER, ObjectType::INTEGER)->
+ setArgs(3, 7)->
+ setDistributedJoins(true)->
+ setReplicatedOnly(false)->
+ setTimeout(10000));
+ $cursor->getAll();
+ $this->assertTrue(true);
+ }
+
+ public function testGetEmptyResults(): void
+ {
+ $tableName = self::TABLE_NAME;
+ $cache = self::$cache;
+ $cursor = $cache->query((new SqlQuery(self::TABLE_NAME, 'field1 > ?'))->setArgs(self::ELEMENTS_NUMBER));
+ $entries = $cursor->getAll();
+ $this->assertEquals(count($entries), 0);
+ $cursor->close();
+
+ $cursor = $cache->query((new SqlQuery(self::TABLE_NAME, 'field1 > ?'))->setArgs(self::ELEMENTS_NUMBER));
+ foreach ($cursor as $entry) {
+ $this->assertTrue(false);
+ }
+ $cursor->close();
+ }
+
+ private function checkCursorResult(CacheEntry $cacheEntry): void
+ {
+ $this->assertEquals($cacheEntry->getValue()->field2, self::generateValue($cacheEntry->getKey()));
+ $this->assertTrue($cacheEntry->getKey() >= 0 && $cacheEntry->getKey() < self::ELEMENTS_NUMBER);
+ }
+
+ private static function generateData(): void
+ {
+ $tableName = self::TABLE_NAME;
+ $cache = self::$cache;
+ $insertQuery = (new SqlFieldsQuery("INSERT INTO {$tableName} (_key, field1, field2) VALUES (?, ?, ?)"))->
+ setArgTypes(ObjectType::INTEGER, ObjectType::INTEGER);
+
+ for ($i = 0; $i < self::ELEMENTS_NUMBER; $i++) {
+ $cache->query($insertQuery->setArgs($i, $i, self::generateValue($i)))->getAll();
+ }
+ }
+
+ private static function generateValue(int $key): string
+ {
+ return 'value' . $key;
+ }
+
+ private static function cleanUp(): void
+ {
+ TestingHelper::destroyCache(self::CACHE_NAME);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/tests/TestConfig.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/TestConfig.php b/modules/platforms/php/tests/TestConfig.php
new file mode 100644
index 0000000..b38f890
--- /dev/null
+++ b/modules/platforms/php/tests/TestConfig.php
@@ -0,0 +1,37 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+class TestConfig
+{
+ public static $endpoints = ['127.0.0.1:10800'];
+ public static $debug = false;
+
+ public static function init(): void
+ {
+ $endpoints = getenv('APACHE_IGNITE_CLIENT_ENDPOINTS');
+ if ($endpoints) {
+ TestConfig::$endpoints = explode(',', $endpoints);
+ }
+ $debug = getenv('APACHE_IGNITE_CLIENT_DEBUG');
+ TestConfig::$debug = ($debug === 'true' || $debug === '1');
+ }
+}
+
+TestConfig::init();
\ No newline at end of file
[6/9] ignite git commit: IGNITE-7783: PHP thin client
Posted by is...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Cache/CacheKeyConfiguration.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Cache/CacheKeyConfiguration.php b/modules/platforms/php/src/Apache/Ignite/Cache/CacheKeyConfiguration.php
new file mode 100644
index 0000000..cbbc249
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Cache/CacheKeyConfiguration.php
@@ -0,0 +1,107 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Cache;
+
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+
+/**
+ * Class representing Cache Key part of Ignite CacheConfiguration.
+ *
+ * All configuration settings are optional and have defaults which are defined on a server side.
+ *
+ * See Apache Ignite documentation for details of every configuration setting.
+ */
+class CacheKeyConfiguration
+{
+ private $typeName;
+ private $affinityKeyFieldName;
+
+ /**
+ * CacheKeyConfiguration constructor.
+ *
+ * @param string|null $typeName
+ * @param string|null $affinityKeyFieldName
+ */
+ public function __construct(string $typeName = null, string $affinityKeyFieldName = null)
+ {
+ $this->typeName = $typeName;
+ $this->affinityKeyFieldName = $affinityKeyFieldName;
+ }
+
+ /**
+ *
+ *
+ * @param string $typeName
+ *
+ * @return CacheKeyConfiguration the same instance of the CacheKeyConfiguration.
+ */
+ public function setTypeName(string $typeName): CacheKeyConfiguration
+ {
+ $this->typeName = $typeName;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getTypeName(): ?string
+ {
+ return $this->typeName;
+ }
+
+ /**
+ *
+ *
+ * @param string $affinityKeyFieldName
+ *
+ * @return CacheKeyConfiguration the same instance of the CacheKeyConfiguration.
+ */
+ public function setAffinityKeyFieldName(string $affinityKeyFieldName): CacheKeyConfiguration
+ {
+ $this->affinityKeyFieldName = $affinityKeyFieldName;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getAffinityKeyFieldName(): ?string
+ {
+ return $this->affinityKeyFieldName;
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function write(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ BinaryCommunicator::writeString($buffer, $this->typeName);
+ BinaryCommunicator::writeString($buffer, $this->affinityKeyFieldName);
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function read(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ $this->typeName = BinaryCommunicator::readString($buffer);
+ $this->affinityKeyFieldName = BinaryCommunicator::readString($buffer);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Cache/QueryEntity.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Cache/QueryEntity.php b/modules/platforms/php/src/Apache/Ignite/Cache/QueryEntity.php
new file mode 100644
index 0000000..6be3c5a
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Cache/QueryEntity.php
@@ -0,0 +1,315 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Cache;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+
+/**
+ * Class representing one Query Entity element of Ignite CacheConfiguration.
+ *
+ * All configuration settings are optional and have defaults which are defined on a server side.
+ *
+ * See Apache Ignite documentation for details of every configuration setting.
+ */
+class QueryEntity
+{
+ private $keyTypeName;
+ private $valueTypeName;
+ private $tableName;
+ private $keyFieldName;
+ private $valueFieldName;
+ private $fields;
+ private $aliases;
+ private $indexes;
+
+ /**
+ * QueryEntity constructor.
+ */
+ public function __construct()
+ {
+ $this->keyTypeName = null;
+ $this->valueTypeName = null;
+ $this->tableName = null;
+ $this->keyFieldName = null;
+ $this->valueFieldName = null;
+ $this->fields = null;
+ $this->aliases = null;
+ $this->indexes = null;
+ }
+
+ /**
+ *
+ *
+ * @param string $keyTypeName
+ *
+ * @return QueryEntity the same instance of the QueryEntity.
+ */
+ public function setKeyTypeName(string $keyTypeName): QueryEntity
+ {
+ $this->keyTypeName = $keyTypeName;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getKeyTypeName(): ?string
+ {
+ return $this->keyTypeName;
+ }
+
+ /**
+ *
+ *
+ * @param string $valueTypeName
+ *
+ * @return QueryEntity the same instance of the QueryEntity.
+ */
+ public function setValueTypeName(string $valueTypeName): QueryEntity
+ {
+ $this->valueTypeName = $valueTypeName;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getValueTypeName(): ?string
+ {
+ return $this->valueTypeName;
+ }
+
+ /**
+ *
+ *
+ * @param string $tableName
+ *
+ * @return QueryEntity the same instance of the QueryEntity.
+ */
+ public function setTableName(string $tableName): QueryEntity
+ {
+ $this->tableName = $tableName;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getTableName(): ?string
+ {
+ return $this->tableName;
+ }
+
+ /**
+ *
+ *
+ * @param string $keyFieldName
+ *
+ * @return QueryEntity the same instance of the QueryEntity.
+ */
+ public function setKeyFieldName(string $keyFieldName): QueryEntity
+ {
+ $this->keyFieldName = $keyFieldName;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getKeyFieldName(): ?string
+ {
+ return $this->keyFieldName;
+ }
+
+ /**
+ *
+ *
+ * @param string $valueFieldName
+ *
+ * @return QueryEntity the same instance of the QueryEntity.
+ */
+ public function setValueFieldName(string $valueFieldName): QueryEntity
+ {
+ $this->valueFieldName = $valueFieldName;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getValueFieldName(): ?string
+ {
+ return $this->valueFieldName;
+ }
+
+ /**
+ *
+ *
+ * @param QueryField ...$fields
+ *
+ * @return QueryEntity the same instance of the QueryEntity.
+ */
+ public function setFields(QueryField ...$fields): QueryEntity
+ {
+ $this->fields = $fields;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return QueryField[]|null
+ */
+ public function getFields(): ?array
+ {
+ return $this->fields;
+ }
+
+ /**
+ *
+ *
+ * @param array[string => string] $aliases
+ *
+ * @return QueryEntity the same instance of the QueryEntity.
+ */
+ public function setAliases(array $aliases): QueryEntity
+ {
+ $this->aliases = $aliases;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return array[string => string]|null
+ */
+ public function getAliases(): ?array
+ {
+ return $this->aliases;
+ }
+
+ /**
+ *
+ *
+ * @param QueryIndex ...$indexes
+ *
+ * @return QueryEntity the same instance of the QueryEntity.
+ */
+ public function setIndexes(QueryIndex ...$indexes): QueryEntity
+ {
+ $this->indexes = $indexes;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return QueryIndex[]|null
+ */
+ public function getIndexes(): ?array
+ {
+ return $this->indexes;
+ }
+
+ private function writeAliases(MessageBuffer $buffer): void
+ {
+ $length = $this->aliases ? count($this->aliases) : 0;
+ $buffer->writeInteger($length);
+ if ($length > 0) {
+ foreach ($this->aliases as $key => $value) {
+ BinaryCommunicator::writeString($buffer, $key);
+ BinaryCommunicator::writeString($buffer, $value);
+ }
+ }
+ }
+
+ private function writeSubEntities(BinaryCommunicator $communicator, MessageBuffer $buffer, ?array $entities): void
+ {
+ $length = $entities ? count($entities) : 0;
+ $buffer->writeInteger($length);
+ if ($length > 0) {
+ foreach ($entities as $entity) {
+ $entity->write($communicator, $buffer);
+ }
+ }
+ }
+
+ private function readAliases(MessageBuffer $buffer): void
+ {
+ $length = $buffer->readInteger();
+ $this->aliases = [];
+ if ($length > 0) {
+ for ($i = 0; $i < $length; $i++) {
+ $this->aliases[BinaryCommunicator::readString($buffer)] = BinaryCommunicator::readString($buffer);
+ }
+ }
+ }
+
+ private function readSubEntities(BinaryCommunicator $communicator, MessageBuffer $buffer, string $subEntityClassName): array
+ {
+ $result = [];
+ $length = $buffer->readInteger();
+ if ($length > 0) {
+ for ($i = 0; $i < $length; $i++) {
+ $entity = new $subEntityClassName();
+ $entity->read($communicator, $buffer);
+ array_push($result, $entity);
+ }
+ }
+ return $result;
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function write(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ BinaryCommunicator::writeString($buffer, $this->keyTypeName);
+ BinaryCommunicator::writeString($buffer, $this->valueTypeName);
+ BinaryCommunicator::writeString($buffer, $this->tableName);
+ BinaryCommunicator::writeString($buffer, $this->keyFieldName);
+ BinaryCommunicator::writeString($buffer, $this->valueFieldName);
+ $this->writeSubEntities($communicator, $buffer, $this->fields);
+ $this->writeAliases($buffer);
+ $this->writeSubEntities($communicator, $buffer, $this->indexes);
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function read(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ $this->keyTypeName = BinaryCommunicator::readString($buffer);
+ $this->valueTypeName = BinaryCommunicator::readString($buffer);
+ $this->tableName = BinaryCommunicator::readString($buffer);
+ $this->keyFieldName = BinaryCommunicator::readString($buffer);
+ $this->valueFieldName = BinaryCommunicator::readString($buffer);
+ $this->fields = $this->readSubEntities($communicator, $buffer, QueryField::class);
+ $this->readAliases($buffer);
+ $this->indexes = $this->readSubEntities($communicator, $buffer, QueryIndex::class);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Cache/QueryField.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Cache/QueryField.php b/modules/platforms/php/src/Apache/Ignite/Cache/QueryField.php
new file mode 100644
index 0000000..55b7724
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Cache/QueryField.php
@@ -0,0 +1,279 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Cache;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Type\ObjectType;
+
+/**
+ * Class representing one Query Field element of QueryEntity of Ignite CacheConfiguration.
+ *
+ * All configuration settings are optional and have defaults which are defined on a server side.
+ *
+ * See Apache Ignite documentation for details of every configuration setting.
+ */
+class QueryField
+{
+ private $name;
+ private $typeName;
+ private $isKeyField;
+ private $isNotNull;
+ private $defaultValue;
+ private $precision;
+ private $scale;
+ private $valueType;
+ private $buffer;
+ private $communicator;
+ private $index;
+
+ /**
+ * QueryField constructor.
+ *
+ * @param string|null $name
+ * @param string|null $typeName
+ */
+ public function __construct(string $name = null, string $typeName = null)
+ {
+ $this->name = $name;
+ $this->typeName = $typeName;
+ $this->isKeyField = false;
+ $this->isNotNull = false;
+ $this->defaultValue = null;
+ $this->precision = -1;
+ $this->scale = -1;
+ $this->valueType = null;
+ $this->buffer = null;
+ $this->communicator = null;
+ $this->index = null;
+ }
+
+ /**
+ *
+ *
+ * @param string $name
+ *
+ * @return QueryField the same instance of the QueryField.
+ */
+ public function setName(string $name): QueryField
+ {
+ $this->name = $name;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getName(): ?string
+ {
+ return $this->name;
+ }
+
+ /**
+ *
+ *
+ * @param string $typeName
+ *
+ * @return QueryField the same instance of the QueryField.
+ */
+ public function setTypeName(string $typeName): QueryField
+ {
+ $this->typeName = $typeName;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getTypeName(): ?string
+ {
+ return $this->typeName;
+ }
+
+ /**
+ *
+ *
+ * @param bool $isKeyField
+ *
+ * @return QueryField the same instance of the QueryField.
+ */
+ public function setIsKeyField(bool $isKeyField): QueryField
+ {
+ $this->isKeyField = $isKeyField;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return bool
+ */
+ public function getIsKeyField(): bool
+ {
+ return $this->isKeyField;
+ }
+
+ /**
+ *
+ *
+ * @param bool $isNotNull
+ *
+ * @return QueryField the same instance of the QueryField.
+ */
+ public function setIsNotNull(bool $isNotNull): QueryField
+ {
+ $this->isNotNull = $isNotNull;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return bool
+ */
+ public function getIsNotNull(): bool
+ {
+ return $this->isNotNull;
+ }
+
+ /**
+ *
+ *
+ * @param mixed $defaultValue
+ * @param int|ObjectType|null $valueType type of the default value:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (or not specified) that means the type is not specified
+ * @return QueryField the same instance of the QueryField.
+ */
+ public function setDefaultValue($defaultValue, $valueType = null): QueryField
+ {
+ $this->defaultValue = $defaultValue;
+ $this->valueType = $valueType;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @param int|ObjectType|null $valueType type of the default value:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (or not specified) that means the type is not specified
+ *
+ * @return mixed
+ *
+ * @throws ClientException if error.
+ */
+ public function getDefaultValue($valueType = null)
+ {
+ if ($this->defaultValue === null) {
+ if ($this->buffer) {
+ $position = $this->buffer->getPosition();
+ $this->buffer->setPosition($this->index);
+ $result = $this->communicator->readObject($this->buffer, $valueType);
+ $this->buffer->setPosition($position);
+ return $result;
+ } else {
+ return null;
+ }
+ } else {
+ return $this->defaultValue;
+ }
+ }
+
+ /**
+ *
+ *
+ * @param int $precision
+ *
+ * @return QueryField the same instance of the QueryField.
+ */
+ public function setPrecision(int $precision): QueryField
+ {
+ $this->precision = $precision;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int
+ */
+ public function getPrecision(): int
+ {
+ return $this->precision;
+ }
+
+ /**
+ *
+ *
+ * @param int $scale
+ *
+ * @return QueryField the same instance of the QueryField.
+ */
+ public function setScale(int $scale): QueryField
+ {
+ $this->scale = $scale;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int
+ */
+ public function getScale(): int
+ {
+ return $this->scale;
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function write(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ BinaryCommunicator::writeString($buffer, $this->name);
+ BinaryCommunicator::writeString($buffer, $this->typeName);
+ $buffer->writeBoolean($this->isKeyField);
+ $buffer->writeBoolean($this->isNotNull);
+ $communicator->writeObject($buffer, $this->defaultValue, $this->valueType);
+ $buffer->writeInteger($this->precision);
+ $buffer->writeInteger($this->scale);
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function read(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ $this->name = BinaryCommunicator::readString($buffer);
+ $this->typeName = BinaryCommunicator::readString($buffer);
+ $this->isKeyField = $buffer->readBoolean();
+ $this->isNotNull = $buffer->readBoolean();
+ $this->defaultValue = null;
+ $this->communicator = $communicator;
+ $this->buffer = $buffer;
+ $this->index = $buffer->getPosition();
+ $communicator->readObject($buffer);
+ $this->precision = $buffer->readInteger();
+ $this->scale = $buffer->readInteger();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Cache/QueryIndex.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Cache/QueryIndex.php b/modules/platforms/php/src/Apache/Ignite/Cache/QueryIndex.php
new file mode 100644
index 0000000..796048f
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Cache/QueryIndex.php
@@ -0,0 +1,191 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Cache;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+
+/**
+ * Class representing one Query Index element of QueryEntity of Ignite CacheConfiguration.
+ *
+ * All configuration settings are optional and have defaults which are defined on a server side.
+ *
+ * See Apache Ignite documentation for details of every configuration setting.
+ */
+class QueryIndex
+{
+ /** @name QueryIndexType
+ * @anchor QueryIndexType
+ * @{
+ */
+ const TYPE_SORTED = 0;
+ const TYPE_FULLTEXT = 1;
+ const TYPE_GEOSPATIAL = 2;
+ /** @} */ // end of QueryIndexType
+
+ private $name;
+ private $type;
+ private $inlineSize;
+ private $fields;
+
+ /**
+ * QueryIndex constructor.
+ *
+ * @param string|null $name
+ * @param int $type one of @ref QueryIndexType constants.
+ *
+ * @throws ClientException if error.
+ */
+ public function __construct(string $name = null, int $type = self::TYPE_SORTED)
+ {
+ $this->name = $name;
+ $this->setType($type);
+ $this->inlineSize = -1;
+ $this->fields = null;
+ }
+
+ /**
+ *
+ *
+ * @param string $name
+ *
+ * @return QueryIndex the same instance of the QueryIndex.
+ */
+ public function setName(string $name): QueryIndex
+ {
+ $this->name = $name;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return string|null
+ */
+ public function getName(): ?string
+ {
+ return $this->name;
+ }
+
+ /**
+ *
+ *
+ * @param int $type one of @ref QueryIndexType constants.
+ *
+ * @return QueryIndex the same instance of the QueryIndex.
+ *
+ * @throws ClientException if error.
+ */
+ public function setType(int $type): QueryIndex
+ {
+ ArgumentChecker::hasValueFrom(
+ $type, 'type', false, [self::TYPE_SORTED, self::TYPE_FULLTEXT, self::TYPE_GEOSPATIAL]);
+ $this->type = $type;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int index type, one of @ref QueryIndexType constants.
+ */
+ public function getType(): int
+ {
+ return $this->type;
+ }
+
+ /**
+ *
+ *
+ * @param int $inlineSize
+ *
+ * @return QueryIndex the same instance of the QueryIndex.
+ */
+ public function setInlineSize(int $inlineSize): QueryIndex
+ {
+ $this->inlineSize = $inlineSize;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return int
+ */
+ public function getInlineSize(): int
+ {
+ return $this->inlineSize;
+ }
+
+ /**
+ *
+ *
+ * @param array[string => bool] $fields
+ *
+ * @return QueryIndex the same instance of the QueryIndex.
+ */
+ public function setFields(array $fields): QueryIndex
+ {
+ $this->fields = $fields;
+ return $this;
+ }
+
+ /**
+ *
+ *
+ * @return array[string => bool]|null
+ */
+ public function getFields(): ?array
+ {
+ return $this->fields;
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function write(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ BinaryCommunicator::writeString($buffer, $this->name);
+ $buffer->writeByte($this->type);
+ $buffer->writeInteger($this->inlineSize);
+ // write fields
+ $length = $this->fields ? count($this->fields) : 0;
+ $buffer->writeInteger($length);
+ if ($length > 0) {
+ foreach ($this->fields as $key => $value) {
+ BinaryCommunicator::writeString($buffer, $key);
+ $buffer->writeBoolean($value);
+ }
+ }
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function read(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ $this->name = BinaryCommunicator::readString($buffer);
+ $this->type = $buffer->readByte();
+ $this->inlineSize = $buffer->readInteger();
+ // read fields
+ $length = $buffer->readInteger();
+ $this->fields = [];
+ if ($length > 0) {
+ $this->fields[BinaryCommunicator::readString($buffer)] = $buffer->readBoolean();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Client.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Client.php b/modules/platforms/php/src/Apache/Ignite/Client.php
new file mode 100644
index 0000000..82847b4
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Client.php
@@ -0,0 +1,243 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Cache\CacheConfiguration;
+use Apache\Ignite\Cache\CacheInterface;
+use Apache\Ignite\Internal\Connection\ClientFailoverSocket;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+use Apache\Ignite\Internal\Utils\Logger;
+use Apache\Ignite\Internal\Binary\ClientOperation;
+use Apache\Ignite\Internal\Cache;
+
+/**
+ * @mainpage Public API specification
+ * The thin client allows your PHP applications to work with Apache Ignite clusters via Binary %Client Protocol.
+ *
+ * This is the public API specification of the client.
+ *
+ * If you open it for the first time, start from the Client class.
+ *
+ * For the usage guide and other instructions see accompanied Apache Ignite PHP %Client documentation.
+ */
+
+/**
+ * Class representing Ignite client.
+ */
+class Client
+{
+ private $socket;
+ private $communicator;
+
+ /**
+ * Public Client constructor.
+ */
+ public function __construct()
+ {
+ $this->socket = new ClientFailoverSocket();
+ $this->communicator = new BinaryCommunicator($this->socket);
+ }
+
+ /**
+ * Connects the client.
+ *
+ * Reconnects if the client already connected.
+ *
+ * @param ClientConfiguration $config the client configuration.
+ *
+ * @throws ClientException if error.
+ */
+ public function connect(ClientConfiguration $config): void
+ {
+ $this->socket->connect($config);
+ }
+
+ /**
+ * Disconnects the client.
+ *
+ * Does nothing if the client already disconnected.
+ */
+ public function disconnect(): void
+ {
+ $this->socket->disconnect();
+ }
+
+ /**
+ * Creates new cache with the provided name and optional configuration.
+ *
+ * @param string $name cache name.
+ * @param CacheConfiguration $cacheConfig optional cache configuration.
+ *
+ * @return CacheInterface new instance of the class with interface representing the created cache.
+ *
+ * @throws ClientException if error.
+ */
+ public function createCache(
+ string $name,
+ CacheConfiguration $cacheConfig = null): CacheInterface
+ {
+ ArgumentChecker::notEmpty($name, 'name');
+ $this->communicator->send(
+ $cacheConfig ?
+ ClientOperation::CACHE_CREATE_WITH_CONFIGURATION :
+ ClientOperation::CACHE_CREATE_WITH_NAME,
+ function (MessageBuffer $payload) use ($name, $cacheConfig)
+ {
+ $this->writeCacheNameOrConfig($payload, $name, $cacheConfig);
+ });
+ return new Cache($name, $this->communicator);
+ }
+
+ /**
+ * Gets existing cache with the provided name
+ * or creates new one with the provided name and optional configuration.
+ *
+ * @param string $name cache name.
+ * @param CacheConfiguration $cacheConfig cache configuration (ignored if cache
+ * with the provided name already exists).
+ *
+ * @return CacheInterface new instance of the class with interface representing the existing or created cache.
+ *
+ * @throws ClientException if error.
+ */
+ public function getOrCreateCache(
+ string $name,
+ CacheConfiguration $cacheConfig = null): CacheInterface
+ {
+ ArgumentChecker::notEmpty($name, 'name');
+ $this->communicator->send(
+ $cacheConfig ?
+ ClientOperation::CACHE_GET_OR_CREATE_WITH_CONFIGURATION :
+ ClientOperation::CACHE_GET_OR_CREATE_WITH_NAME,
+ function (MessageBuffer $payload) use ($name, $cacheConfig)
+ {
+ $this->writeCacheNameOrConfig($payload, $name, $cacheConfig);
+ });
+ return new Cache($name, $this->communicator);
+ }
+
+ /**
+ * Gets instance of the class with interface representing the cache with the provided name.
+ * The method does not check if the cache with the provided name exists.
+ *
+ * @param string $name cache name.
+ *
+ * @return CacheInterface new instance of the class with interface representing the cache.
+ *
+ * @throws ClientException if error.
+ */
+ public function getCache(string $name): CacheInterface
+ {
+ ArgumentChecker::notEmpty($name, 'name');
+ return new Cache($name, $this->communicator);
+ }
+
+ /**
+ * Destroys cache with the provided name.
+ *
+ * @param string $name cache name.
+ *
+ * @throws ClientException if error.
+ */
+ public function destroyCache(string $name): void
+ {
+ ArgumentChecker::notEmpty($name, 'name');
+ $this->communicator->send(
+ ClientOperation::CACHE_DESTROY,
+ function (MessageBuffer $payload) use ($name)
+ {
+ $payload->writeInteger(Cache::calculateId($name));
+ });
+ }
+
+ /**
+ * Returns configuration of cache with the provided name.
+ *
+ * @param string $name cache name.
+ *
+ * @return CacheConfiguration cache configuration.
+ *
+ * @throws ClientException if error.
+ */
+ public function getCacheConfiguration(string $name): CacheConfiguration
+ {
+ ArgumentChecker::notEmpty($name, 'name');
+ $config = null;
+ $this->communicator->send(
+ ClientOperation::CACHE_GET_CONFIGURATION,
+ function (MessageBuffer $payload) use ($name)
+ {
+ $payload->writeInteger(Cache::calculateId($name));
+ $payload->writeByte(0);
+ },
+ function (MessageBuffer $payload) use (&$config)
+ {
+ $config = new CacheConfiguration();
+ $config->read($this->communicator, $payload);
+ });
+ return $config;
+ }
+
+ /**
+ * Gets existing cache names.
+ *
+ * @return array array with the existing cache names.
+ * The array is empty if no caches exist.
+ *
+ * @throws ClientException if error.
+ */
+ public function cacheNames(): array
+ {
+ $names = null;
+ $this->communicator->send(
+ ClientOperation::CACHE_GET_NAMES,
+ null,
+ function (MessageBuffer $payload) use (&$names)
+ {
+ $names = $this->communicator->readStringArray($payload);
+ });
+ return $names;
+ }
+
+ /**
+ * Enables/disables the Ignite client's debug output (including errors logging).
+ * Disabled by default.
+ *
+ * @param bool $value true to enable, false to disable.
+ */
+ public function setDebug(bool $value): void
+ {
+ Logger::setDebug($value);
+ }
+
+ private function writeCacheNameOrConfig(
+ MessageBuffer $buffer,
+ string $name,
+ CacheConfiguration $cacheConfig = null): void
+ {
+ if ($cacheConfig) {
+ $cacheConfig->write($this->communicator, $buffer, $name);
+ } else {
+ $this->communicator->writeString($buffer, $name);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/ClientConfiguration.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/ClientConfiguration.php b/modules/platforms/php/src/Apache/Ignite/ClientConfiguration.php
new file mode 100644
index 0000000..e10f010
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/ClientConfiguration.php
@@ -0,0 +1,294 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+
+/**
+ * Class representing Ignite client configuration.
+ *
+ * The configuration includes:
+ * - (mandatory) Ignite node endpoint(s)
+ * - (optional) user credentials for authentication
+ * - (optional) TLS options for secure connection
+ * - (optional) connection options
+ */
+class ClientConfiguration
+{
+ private $endpoints;
+ private $userName;
+ private $password;
+ private $tlsOptions;
+ private $timeout;
+ private $sendChunkSize;
+ private $receiveChunkSize;
+ private $tcpNoDelay;
+
+ const ENDPOINT_PORT_DEFAULT = 10800;
+
+ /**
+ * Creates an instance of Ignite client configuration
+ * with the provided mandatory settings and default optional settings.
+ *
+ * By default, the client does not use authentication and secure connection.
+ *
+ * @param string ...$endpoints Ignite node endpoint(s). The client randomly connects/reconnects
+ * to one of the specified node.
+ *
+ * @throws ClientException if error.
+ */
+ public function __construct(string ...$endpoints)
+ {
+ ArgumentChecker::notEmpty($endpoints, 'endpoints');
+ $this->endpoints = array_map(array($this, 'parseEndpoint'), $endpoints);
+ $this->userName = null;
+ $this->password = null;
+ $this->tlsOptions = null;
+ $this->timeout = 0;
+ $this->sendChunkSize = 0;
+ $this->receiveChunkSize = 0;
+ $this->tcpNoDelay = true;
+ }
+
+ /**
+ * Returns Ignite node endpoints specified in the constructor.
+ *
+ * @return string[] endpoints
+ */
+ public function getEndpoints(): array
+ {
+ return $this->endpoints;
+ }
+
+ /**
+ * Sets username which will be used for authentication during the client's connection.
+ *
+ * If username is not set, the client does not use authentication during connection.
+ *
+ * @param string|null $userName username. If null, authentication is disabled.
+ *
+ * @return ClientConfiguration the same instance of the ClientConfiguration.
+ */
+ public function setUserName(?string $userName): ClientConfiguration
+ {
+ $this->userName = $userName;
+ return $this;
+ }
+
+ /**
+ * Returns the current username.
+ *
+ * @return string|null username or null (if authentication is disabled).
+ */
+ public function getUserName(): ?string
+ {
+ return $this->userName;
+ }
+
+ /**
+ * Sets password which will be used for authentication during the client's connection.
+ *
+ * Password is ignored, if username is not set.
+ * If password is not set, it is considered empty.
+ *
+ * @param string|null $password password. If null, password is empty.
+ *
+ * @return ClientConfiguration the same instance of the ClientConfiguration.
+ */
+ public function setPassword(?string $password): ClientConfiguration
+ {
+ $this->password = $password;
+ return $this;
+ }
+
+ /**
+ * Returns the current password.
+ *
+ * @return string|null password or null (if password is empty).
+ */
+ public function getPassword(): ?string
+ {
+ return $this->password;
+ }
+
+ /**
+ * Enables and setup TLS connection.
+ *
+ * If not enabled (by default), the client does not use secure connection.
+ *
+ * @param array|null $tlsOptions TLS connection options in the format defined here: http://php.net/manual/en/context.ssl.php
+ * If null, secure connection is not used.
+ *
+ * @return ClientConfiguration the same instance of the ClientConfiguration.
+ */
+ public function setTLSOptions(?array $tlsOptions): ClientConfiguration
+ {
+ $this->tlsOptions = $tlsOptions;
+ return $this;
+ }
+
+ /**
+ * Returns the current TLS connection options.
+ *
+ * @return array|null TLS connection options or null (if secure connection is not used).
+ */
+ public function getTLSOptions(): ?array
+ {
+ return $this->tlsOptions;
+ }
+
+ /**
+ * Sets send/receive timeout.
+ *
+ * Default value is defined by the PHP settings.
+ *
+ * @param int $timeout send/receive timeout (in milliseconds).
+ *
+ * @return ClientConfiguration the same instance of the ClientConfiguration.
+ */
+ public function setTimeout(int $timeout): ClientConfiguration
+ {
+ $this->timeout = $timeout;
+ return $this;
+ }
+
+ /**
+ * Returns the current send/receive timeout.
+ *
+ * @return int send/receive timeout (in milliseconds).
+ */
+ public function getTimeout(): int
+ {
+ return $this->timeout;
+ }
+
+ /**
+ * Sets the size of the send chunk.
+ *
+ * 8192 bytes by default.
+ *
+ * @param int $size size of the send chunk (in bytes).
+ *
+ * @return ClientConfiguration the same instance of the ClientConfiguration.
+ */
+ public function setSendChunkSize(int $size): ClientConfiguration
+ {
+ $this->sendChunkSize = $size;
+ return $this;
+ }
+
+ /**
+ * Returns the current size of the send chunk.
+ *
+ * @return int size of the send chunk (in bytes).
+ */
+ public function getSendChunkSize(): int
+ {
+ return $this->sendChunkSize;
+ }
+
+ /**
+ * Sets the size of the receive chunk.
+ *
+ * 8192 bytes by default.
+ *
+ * @param int $size size of the receive chunk (in bytes).
+ *
+ * @return ClientConfiguration the same instance of the ClientConfiguration.
+ */
+ public function setReceiveChunkSize(int $size): ClientConfiguration
+ {
+ $this->receiveChunkSize = $size;
+ return $this;
+ }
+
+ /**
+ * Returns the current size of the receive chunk.
+ *
+ * @return int size of the receive chunk (in bytes).
+ */
+ public function getReceiveChunkSize(): int
+ {
+ return $this->receiveChunkSize;
+ }
+
+ /**
+ * Disables/enables the TCP Nagle algorithm.
+ *
+ * Enabled by default.
+ *
+ * @param bool $tcpNoDelay true to enable, false to disable.
+ *
+ * @return ClientConfiguration the same instance of the ClientConfiguration.
+ */
+ public function setTcpNoDelay(bool $tcpNoDelay): ClientConfiguration
+ {
+ $this->tcpNoDelay = $tcpNoDelay;
+ return $this;
+ }
+
+ /**
+ * Returns the current status of the TCP Nagle algorithm.
+ *
+ * @return bool true if enabled, false if disabled.
+ */
+ public function getTcpNoDelay(): bool
+ {
+ return $this->tcpNoDelay;
+ }
+
+ private function parseEndpoint(string $endpoint): string
+ {
+ $endpoint = trim($endpoint);
+ $host = $endpoint;
+ $port = null;
+ $parsed = explode(':', $endpoint);
+ if (count($parsed) > 2) {
+ // IPv6 address
+ $index = strrpos($endpoint, ']:');
+ if ($index !== false) {
+ $host = substr($endpoint, 0, $index + 1);
+ $port = substr($endpoint, $index + 2);
+ }
+ $first = $host[0];
+ $last = $host[strlen($host) - 1];
+ if ($first === '[' || $last === ']') {
+ if (!($first === '[' && $last === ']')) {
+ ArgumentChecker::illegalArgument('Incorrect endpoint format: ' . $endpoint);
+ }
+ } else {
+ $host = sprintf('[%s]', $host);
+ }
+ }
+ else {
+ // IPv4 address
+ $host = $parsed[0];
+ if (count($parsed) === 2) {
+ $port = $parsed[1];
+ }
+ }
+ if ($port === null) {
+ $port = self::ENDPOINT_PORT_DEFAULT;
+ } elseif (!ctype_digit($port)) {
+ ArgumentChecker::illegalArgument('Incorrect endpoint format: ' . $endpoint);
+ }
+ return sprintf('%s:%s', $host, $port);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Data/BinaryObject.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Data/BinaryObject.php b/modules/platforms/php/src/Apache/Ignite/Data/BinaryObject.php
new file mode 100644
index 0000000..92a3294
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Data/BinaryObject.php
@@ -0,0 +1,469 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Data;
+
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Type\ComplexObjectType;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Binary\BinaryTypeBuilder;
+use Apache\Ignite\Internal\Binary\BinaryObjectField;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+use Apache\Ignite\Internal\Binary\BinaryField;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+use Apache\Ignite\Internal\Utils\Logger;
+
+/**
+ * Class representing a complex Ignite object in the binary form.
+ *
+ * It corresponds to ObjectType::COMPLEX_OBJECT,
+ * has mandatory type Id, which corresponds to a name of the complex type,
+ * and includes optional fields.
+ *
+ * An instance of the BinaryObject can be obtained/created by the following ways:
+ * - returned by the client when a complex object is received from Ignite cache
+ * and is not deserialized to another PHP object.
+ * - created using the public constructor. Fields may be added to such an instance using setField() method.
+ * - created from a PHP object using static fromObject() method.
+ */
+class BinaryObject
+{
+ const HEADER_LENGTH = 24;
+ const VERSION = 1;
+
+ // user type
+ const FLAG_USER_TYPE = 0x0001;
+ // schema exists
+ const FLAG_HAS_SCHEMA = 0x0002;
+ // object contains raw data
+ const FLAG_HAS_RAW_DATA = 0x0004;
+ // offsets take 1 byte
+ const FLAG_OFFSET_ONE_BYTE = 0x0008;
+ // offsets take 2 bytes
+ const FLAG_OFFSET_TWO_BYTES = 0x0010;
+ // compact footer, no field IDs
+ const FLAG_COMPACT_FOOTER = 0x0020;
+
+ private $typeName;
+ private $fields;
+ private $typeBuilder;
+ private $modified;
+ private $buffer;
+ private $schemaOffset;
+ private $hasSchema;
+ private $compactFooter;
+ private $hasRawData;
+ private $offsetType;
+ private $startPos;
+ private $length;
+
+ /**
+ * Creates an instance of the BinaryObject without any fields.
+ *
+ * Fields may be added later using setField() method.
+ *
+ * @param string $typeName name of the complex type to generate the type Id.
+ *
+ * @throws ClientException if error.
+ */
+ public function __construct(string $typeName)
+ {
+ ArgumentChecker::notEmpty($typeName, 'typeName');
+ $this->typeName = $typeName;
+ $this->fields = [];
+ $this->typeBuilder = BinaryTypeBuilder::fromTypeName($typeName);
+ $this->modified = false;
+ $this->buffer = null;
+ $this->schemaOffset = null;
+ $this->hasSchema = false;
+ $this->compactFooter = false;
+ $this->hasRawData = false;
+ }
+
+ /**
+ * Creates an instance of the BinaryObject from the specified instance of PHP class.
+ *
+ * All public properties of the PHP object with their values are added as fields
+ * to the BinaryObject.
+ * Fields may be added or removed later using setField() and removeField() methods.
+ *
+ * If complexObjectType parameter is specified, then the type Id is taken from it.
+ * Otherwise, the type Id is generated from the name of the PHP class which instance is specified.
+ *
+ * @param object $object instance of PHP class which adds and initializes the fields
+ * of the BinaryObject instance.
+ * @param ComplexObjectType $complexObjectType instance of complex type definition
+ * which specifies non-standard mapping of the fields of the BinaryObject instance
+ * to/from the Ignite types.
+ *
+ * @return BinaryObject new BinaryObject instance.
+ *
+ * @throws ClientException if error.
+ */
+ public static function fromObject(object $object, ComplexObjectType $complexObjectType = null): BinaryObject
+ {
+ $typeBuilder = BinaryTypeBuilder::fromObject($object, $complexObjectType);
+ $result = new BinaryObject($typeBuilder->getTypeName());
+ $result->typeBuilder = $typeBuilder;
+ try {
+ $class = new \ReflectionClass($object);
+ foreach ($typeBuilder->getFields() as $field) {
+ $fieldName = $field->getName();
+ if ($class->hasProperty($fieldName)) {
+ $result->setField(
+ $fieldName,
+ $class->getProperty($fieldName)->getValue($object),
+ $complexObjectType ? $complexObjectType->getFieldType($fieldName) : null);
+ } else {
+ BinaryUtils::serializationError(true, sprintf('field "%s" does not exist', $fieldName));
+ }
+ }
+ } catch (\ReflectionException $e) {
+ BinaryUtils::serializationError(true, sprintf('class "%s" does not exist', get_class($object)));
+ }
+ return $result;
+ }
+
+ /**
+ * Sets new value of the specified field.
+ * Adds the specified field, if it did not exist before.
+ *
+ * Optionally, specifies an Ignite type of the field.
+ * If the type is not specified then the Ignite client
+ * tries to make automatic mapping between PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * @param string $fieldName name of the field.
+ * @param mixed $fieldValue new value of the field.
+ * @param int|ObjectType|null $fieldType Ignite type of the field:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (or not specified) that means the type is not specified
+ *
+ * @return BinaryObject the same instance of BinaryObject.
+ *
+ * @throws ClientException if error.
+ */
+ public function setField(string $fieldName, $fieldValue, $fieldType = null): BinaryObject
+ {
+ ArgumentChecker::notEmpty($fieldName, 'fieldName');
+ BinaryUtils::checkObjectType($fieldType, 'fieldType');
+ $this->modified = true;
+ $field = new BinaryObjectField($fieldName, $fieldValue, $fieldType);
+ $this->fields[$field->getId()] = $field;
+ $this->typeBuilder->setField($fieldName, $field->getTypeCode());
+ return $this;
+ }
+
+ /**
+ * Removes the specified field.
+ * Does nothing if the field does not exist.
+ *
+ * @param string $fieldName name of the field.
+ *
+ * @return BinaryObject the same instance of BinaryObject.
+ *
+ * @throws ClientException if error.
+ */
+ public function removeField(string $fieldName): BinaryObject
+ {
+ ArgumentChecker::notEmpty($fieldName, 'fieldName');
+ $this->modified = true;
+ $fieldId = BinaryField::calculateId($fieldName);
+ if (array_key_exists($fieldId, $this->fields)) {
+ unset($this->fields[$fieldId]);
+ }
+ $this->typeBuilder->removeField($fieldName);
+ return $this;
+ }
+
+ /**
+ * Checks if the specified field exists in this BinaryObject instance.
+ *
+ * @param string $fieldName name of the field.
+ *
+ * @return bool true if exists, false otherwise.
+ *
+ * @throws ClientException if error.
+ */
+ public function hasField(string $fieldName): bool
+ {
+ ArgumentChecker::notEmpty($fieldName, 'fieldName');
+ $fieldId = BinaryField::calculateId($fieldName);
+ return array_key_exists($fieldId, $this->fields);
+ }
+
+ /**
+ * Returns a value of the specified field.
+ *
+ * Optionally, specifies Ignite type of the field.
+ * If the type is not specified then the Ignite client
+ * tries to make automatic mapping between PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * If field with the specified name doesn't exist, throws Exception::ClientException.
+ * Use hasField() method to ensure the field exists.
+ *
+ * @param string $fieldName name of the field.
+ * @param int|ObjectType|null $fieldType Ignite type of the field:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (or not specified) that means the type is not specified
+ *
+ * @return mixed value of the field.
+ *
+ * @throws ClientException if error.
+ */
+ public function getField(string $fieldName, $fieldType = null)
+ {
+ ArgumentChecker::notEmpty($fieldName, 'fieldName');
+ BinaryUtils::checkObjectType($fieldType, 'fieldType');
+ $fieldId = BinaryField::calculateId($fieldName);
+ if (array_key_exists($fieldId, $this->fields)) {
+ return $this->fields[$fieldId]->getValue($fieldType);
+ }
+ throw new ClientException(sprintf('Field %s does not exist', $fieldName));
+ }
+
+ /**
+ * Deserializes this BinaryObject instance into PHP object which corresponds to the specified complex object type.
+ *
+ * @param ComplexObjectType $complexObjectType instance of class representing complex object type.
+ *
+ * @return object instance of the PHP object which corresponds to the specified complex object type.
+ *
+ * @throws ClientException if error.
+ */
+ public function toObject(ComplexObjectType $complexObjectType): object
+ {
+ $className = $complexObjectType->getPhpClassName();
+ if (!$className) {
+ $className = $this->getTypeName();
+ }
+ if (!class_exists($className)) {
+ BinaryUtils::serializationError(false, sprintf('class "%s" does not exist', $className));
+ }
+ $result = new $className;
+ foreach ($this->fields as $field) {
+ $binaryField = $this->typeBuilder->getField($field->getId());
+ if (!$binaryField) {
+ BinaryUtils::serializationError(
+ false, sprintf('field with id "%s" can not be deserialized', $field->getId()));
+ }
+ $fieldName = $binaryField->getName();
+ $result->$fieldName = $field->getValue($complexObjectType->getFieldType($fieldName));
+ }
+ return $result;
+ }
+
+ /**
+ * Returns type name of this BinaryObject instance.
+ *
+ * @return string type name.
+ */
+ public function getTypeName(): string
+ {
+ return $this->typeBuilder->getTypeName();
+ }
+
+ /**
+ * Returns names of all fields in this BinaryObject instance.
+ *
+ * @return array names of all fields.
+ *
+ * @throws ClientException if error.
+ */
+ public function getFieldNames(): array
+ {
+ return array_map(
+ function (int $fieldId): string
+ {
+ $field = $this->typeBuilder->getField($fieldId);
+ if ($field) {
+ return $field->getName();
+ } else {
+ BinaryUtils::internalError(
+ sprintf('Field "%s" is absent in binary type fields', $fieldId));
+ }
+ return null;
+ },
+ $this->typeBuilder->getSchema()->getFieldIds());
+ }
+
+ private static function isFlagSet(int $flags, int $flag): bool
+ {
+ return ($flags & $flag) === $flag;
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public static function fromBuffer(BinaryCommunicator $communicator, MessageBuffer $buffer): BinaryObject
+ {
+ $result = new BinaryObject(' ');
+ $result->buffer = $buffer;
+ $result->startPos = $buffer->getPosition();
+ $result->read($communicator);
+ return $result;
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function write(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ if ($this->buffer && !$this->modified) {
+ $buffer->writeBuffer($this->buffer, $this->startPos, $this->length);
+ } else {
+ $this->typeBuilder->finalize($communicator);
+ $this->startPos = $buffer->getPosition();
+ $buffer->setPosition($this->startPos + BinaryObject::HEADER_LENGTH);
+ $this->hasSchema = count($this->fields) > 0;
+ if ($this->hasSchema) {
+ // write fields
+ $field = null;
+ foreach ($this->fields as $field) {
+ $field->writeValue($communicator, $buffer, ($this->typeBuilder->getField($field->getId()))->getTypeCode());
+ }
+ $this->schemaOffset = $buffer->getPosition() - $this->startPos;
+ $this->offsetType = $field->getOffsetType($this->startPos);
+ // write schema
+ foreach ($this->fields as $field) {
+ $field->writeOffset($buffer, $this->startPos, $this->offsetType);
+ }
+ } else {
+ $this->schemaOffset = 0;
+ }
+ $this->length = $buffer->getPosition() - $this->startPos;
+ $this->buffer = $buffer;
+ // write header
+ $this->writeHeader();
+ $this->buffer->setPosition($this->startPos + $this->length);
+ $this->modified = false;
+ }
+
+ if (Logger::isDebug()) {
+ Logger::logDebug('BinaryObject::write');
+ Logger::logBuffer($this->buffer, $this->startPos, $this->length);
+ }
+ }
+
+ private function writeHeader(): void
+ {
+ $this->buffer->setPosition($this->startPos);
+ // type code
+ $this->buffer->writeByte(ObjectType::COMPLEX_OBJECT);
+ // version
+ $this->buffer->writeByte(BinaryObject::VERSION);
+ // flags
+ $flags = BinaryObject::FLAG_USER_TYPE;
+ if ($this->hasSchema) {
+ $flags = $flags | BinaryObject::FLAG_COMPACT_FOOTER | BinaryObject::FLAG_HAS_SCHEMA;
+ }
+ if ($this->offsetType === ObjectType::BYTE) {
+ $flags = $flags | BinaryObject::FLAG_OFFSET_ONE_BYTE;
+ } elseif ($this->offsetType === ObjectType::SHORT) {
+ $flags = $flags | BinaryObject::FLAG_OFFSET_TWO_BYTES;
+ }
+ $this->buffer->writeShort($flags);
+ // type id
+ $this->buffer->writeInteger($this->typeBuilder->getTypeId());
+ // hash code
+ $this->buffer->writeInteger(BinaryUtils::contentHashCode(
+ $this->buffer, $this->startPos + BinaryObject::HEADER_LENGTH, $this->schemaOffset - 1));
+ // length
+ $this->buffer->writeInteger($this->length);
+ // schema id
+ $this->buffer->writeInteger($this->hasSchema ? $this->typeBuilder->getSchemaId() : 0);
+ // schema offset
+ $this->buffer->writeInteger($this->schemaOffset);
+ }
+
+ private function read(BinaryCommunicator $communicator): void
+ {
+ $this->readHeader($communicator);
+ if ($this->hasSchema) {
+ $this->buffer->setPosition($this->startPos + $this->schemaOffset);
+ $fieldOffsets = [];
+ $fieldIds = $this->typeBuilder->getSchema()->getFieldIds();
+ $index = 0;
+ $schemaEndOffset = $this->startPos + $this->length;
+ if ($this->hasRawData) {
+ $schemaEndOffset -= TypeInfo::getTypeInfo(ObjectType::INTEGER)->getSize();
+ }
+ while ($this->buffer->getPosition() < $schemaEndOffset) {
+ if (!$this->compactFooter) {
+ $fieldId = $this->buffer->readInteger();
+ $this->typeBuilder->getSchema()->addField($fieldId);
+ } else {
+ if ($index >= count($fieldIds)) {
+ BinaryUtils::serializationError(
+ false, 'wrong number of fields in schema');
+ }
+ $fieldId = $fieldIds[$index];
+ $index++;
+ }
+ array_push($fieldOffsets, [$fieldId, $this->buffer->readNumber($this->offsetType, false)]);
+ }
+ usort($fieldOffsets,
+ function (array $val1, array $val2): int
+ {
+ return $val1[1] - $val2[1];
+ });
+ for ($i = 0; $i < count($fieldOffsets); $i++) {
+ $fieldId = $fieldOffsets[$i][0];
+ $offset = $fieldOffsets[$i][1];
+ $nextOffset = $i + 1 < count($fieldOffsets) ? $fieldOffsets[$i + 1][1] : $this->schemaOffset;
+ $field = BinaryObjectField::fromBuffer(
+ $communicator, $this->buffer, $this->startPos + $offset, $nextOffset - $offset, $fieldId);
+ $this->fields[$field->getId()] = $field;
+ }
+ }
+ $this->buffer->setPosition($this->startPos + $this->length);
+ }
+
+ private function readHeader(BinaryCommunicator $communicator): void
+ {
+ // type code
+ $this->buffer->readByte();
+ // version
+ $version = $this->buffer->readByte();
+ if ($version !== BinaryObject::VERSION) {
+ BinaryUtils::internalError();
+ }
+ // flags
+ $flags = $this->buffer->readShort();
+ // type id
+ $typeId = $this->buffer->readInteger();
+ // hash code
+ $this->buffer->readInteger();
+ // length
+ $this->length = $this->buffer->readInteger();
+ // schema id
+ $schemaId = $this->buffer->readInteger();
+ // schema offset
+ $this->schemaOffset = $this->buffer->readInteger();
+ $this->hasSchema = BinaryObject::isFlagSet($flags, BinaryObject::FLAG_HAS_SCHEMA);
+ $this->compactFooter = BinaryObject::isFlagSet($flags, BinaryObject::FLAG_COMPACT_FOOTER);
+ $this->hasRawData = BinaryObject::isFlagSet($flags, BinaryObject::FLAG_HAS_RAW_DATA);
+ $this->offsetType = BinaryObject::isFlagSet($flags, BinaryObject::FLAG_OFFSET_ONE_BYTE) ?
+ ObjectType::BYTE :
+ (BinaryObject::isFlagSet($flags, BinaryObject::FLAG_OFFSET_TWO_BYTES) ?
+ ObjectType::SHORT :
+ ObjectType::INTEGER);
+ $this->typeBuilder = BinaryTypeBuilder::fromTypeId($communicator, $typeId, $this->compactFooter ? $schemaId : null);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Data/Date.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Data/Date.php b/modules/platforms/php/src/Apache/Ignite/Data/Date.php
new file mode 100644
index 0000000..356cc36
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Data/Date.php
@@ -0,0 +1,84 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Data;
+
+use \DateTime;
+
+/**
+ * Class representing Ignite Date type
+ * (number of milliseconds elapsed since January 1, 1970, 00:00:00 UTC).
+ */
+class Date
+{
+ private $millis;
+
+ /**
+ * Public constructor.
+ *
+ * @param float $millis integer number of milliseconds elapsed since January 1, 1970, 00:00:00 UTC.
+ */
+ public function __construct(float $millis)
+ {
+ $this->millis = $millis;
+ }
+
+ /**
+ * Creates Date instance from DateTime instance.
+ *
+ * @param DateTime $dateTime DateTime instance.
+ *
+ * @return Date new Date instance.
+ */
+ public static function fromDateTime(DateTime $dateTime)
+ {
+ return new Date($dateTime->getTimestamp() * 1000);
+ }
+
+ /**
+ * Returns the date value as DateTime instance.
+ *
+ * @return DateTime new DateTime instance.
+ */
+ public function toDateTime(): DateTime
+ {
+ $dateTime = new DateTime();
+ $dateTime->setTimestamp($this->getSeconds());
+ return $dateTime;
+ }
+
+ /**
+ * Returns the date value as number of milliseconds elapsed since January 1, 1970, 00:00:00 UTC.
+ *
+ * @return float number of milliseconds elapsed since January 1, 1970, 00:00:00 UTC.
+ */
+ public function getMillis(): float
+ {
+ return $this->millis;
+ }
+
+ /**
+ * Returns the date value as number of seconds elapsed since January 1, 1970, 00:00:00 UTC.
+ *
+ * @return float number of seconds elapsed since January 1, 1970, 00:00:00 UTC.
+ */
+ public function getSeconds(): float
+ {
+ return $this->millis / 1000;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Data/EnumItem.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Data/EnumItem.php b/modules/platforms/php/src/Apache/Ignite/Data/EnumItem.php
new file mode 100644
index 0000000..3178006
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Data/EnumItem.php
@@ -0,0 +1,155 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Data;
+
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+use Apache\Ignite\Exception\ClientException;
+
+/**
+ * Class representing an item of Ignite enum type.
+ *
+ * The item is defined by:
+ * - type Id (mandatory) - Id of the Ignite enum type.
+ * - ordinal (optional) - ordinal of the item in the Ignite enum type.
+ * - name (optional) - name of the item (field name in the Ignite enum type).
+ * - value (optional) - value of the item.
+ * Usually, at least one from the optional ordinal, name or value must be specified
+ * in order to use an instance of this class in Ignite operations.
+ *
+ * To distinguish one item from another, the Ignite client analyzes the optional fields in the following order:
+ * ordinal, name, value.
+ */
+class EnumItem
+{
+ private $typeId;
+ private $ordinal;
+ private $name;
+ private $value;
+
+ /**
+ * Public constructor.
+ *
+ * @param int $typeId Id of the Ignite enum type.
+ */
+ public function __construct(int $typeId)
+ {
+ $this->setTypeId($typeId);
+ $this->ordinal = null;
+ $this->name = null;
+ $this->value = null;
+ }
+
+ /**
+ * Returns Id of the Ignite enum type.
+ *
+ * @return int Id of the enum type.
+ */
+ public function getTypeId(): int
+ {
+ return $this->typeId;
+ }
+
+ /**
+ * Updates Id of the Ignite enum type.
+ *
+ * @param int $typeId new Id of the Ignite enum type.
+ *
+ * @return EnumItem the same instance of EnumItem.
+ */
+ public function setTypeId(int $typeId): EnumItem
+ {
+ $this->typeId = $typeId;
+ return $this;
+ }
+
+ /**
+ * Returns ordinal of the item in the Ignite enum type
+ * or null if ordinal is not set.
+ *
+ * @return int|null ordinal of the item in the Ignite enum type or null (if ordinal is not set).
+ */
+ public function getOrdinal(): ?int
+ {
+ return $this->ordinal;
+ }
+
+ /**
+ * Sets or updates ordinal of the item in the Ignite enum type.
+ *
+ * @param int $ordinal ordinal of the item in the Ignite enum type.
+ *
+ * @return EnumItem the same instance of EnumItem.
+ */
+ public function setOrdinal(int $ordinal): EnumItem
+ {
+ $this->ordinal = $ordinal;
+ return $this;
+ }
+
+ /**
+ * Returns name of the item
+ * or null if name is not set.
+ *
+ * @return string|null name of the item or null (if name is not set).
+ */
+ public function getName(): ?string
+ {
+ return $this->name;
+ }
+
+ /**
+ * Sets or updates name of the item.
+ *
+ * @param string $name name of the item.
+ *
+ * @return EnumItem the same instance of EnumItem.
+ *
+ * @throws ClientException if error.
+ */
+ public function setName(string $name): EnumItem
+ {
+ ArgumentChecker::notEmpty($name, 'name');
+ $this->name = $name;
+ return $this;
+ }
+
+ /**
+ * Returns value of the item
+ * or null if value is not set.
+ *
+ * @return int|null value of the item or null (if value is not set).
+ */
+ public function getValue(): ?int
+ {
+ return $this->value;
+ }
+
+ /**
+ * Sets or updates value of the item.
+ *
+ * @param int $value value of the item.
+ *
+ * @return EnumItem the same instance of EnumItem.
+ */
+ public function setValue(int $value): EnumItem
+ {
+ $this->value = $value;
+ return $this;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Data/Time.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Data/Time.php b/modules/platforms/php/src/Apache/Ignite/Data/Time.php
new file mode 100644
index 0000000..9d0388a
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Data/Time.php
@@ -0,0 +1,58 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Data;
+
+/**
+ * Class representing Ignite Time type
+ * (number of milliseconds elapsed since midnight, i.e. 00:00:00 UTC).
+ */
+class Time
+{
+ private $millis;
+
+ /**
+ * Public constructor.
+ *
+ * @param int $millis number of milliseconds elapsed since midnight, i.e. 00:00:00 UTC.
+ */
+ public function __construct(int $millis)
+ {
+ $this->millis = $millis;
+ }
+
+ /**
+ * Returns the time value as number of milliseconds elapsed since midnight, i.e. 00:00:00 UTC.
+ *
+ * @return int number of milliseconds elapsed since midnight, i.e. 00:00:00 UTC.
+ */
+ public function getMillis(): int
+ {
+ return $this->millis;
+ }
+
+ /**
+ * Returns the time value as number of seconds elapsed since midnight, i.e. 00:00:00 UTC.
+ *
+ * @return int number of seconds elapsed since midnight, i.e. 00:00:00 UTC.
+ */
+ public function getSeconds(): int
+ {
+ return $this->millis / 1000;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Data/Timestamp.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Data/Timestamp.php b/modules/platforms/php/src/Apache/Ignite/Data/Timestamp.php
new file mode 100644
index 0000000..39ef984
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Data/Timestamp.php
@@ -0,0 +1,64 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Data;
+
+use \DateTime;
+
+/**
+ * Class representing Ignite Timestamp type
+ * (Ignite Date with additional nanoseconds fraction of the last millisecond).
+ */
+class Timestamp extends Date
+{
+ private $nanos;
+
+ /**
+ * Public constructor.
+ *
+ * @param float $millis integer number of milliseconds elapsed since January 1, 1970, 00:00:00 UTC.
+ * @param int $nanos nanoseconds of the last millisecond, should be in the range from 0 to 999999.
+ */
+ public function __construct(float $millis, int $nanos)
+ {
+ parent::__construct($millis);
+ $this->nanos = $nanos;
+ }
+
+ /**
+ * Creates Timestamp instance from DateTime instance.
+ *
+ * @param DateTime $dateTime DateTime instance.
+ *
+ * @return Timestamp new Timestamp instance.
+ */
+ public static function fromDateTime(DateTime $dateTime)
+ {
+ return new Timestamp($dateTime->getTimestamp() * 1000, 0);
+ }
+
+ /**
+ * Returns the nanoseconds of the last millisecond from the timestamp.
+ *
+ * @return int nanoseconds of the last millisecond.
+ */
+ public function getNanos(): int
+ {
+ return $this->nanos;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Exception/ClientException.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Exception/ClientException.php b/modules/platforms/php/src/Apache/Ignite/Exception/ClientException.php
new file mode 100644
index 0000000..88fe56b
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Exception/ClientException.php
@@ -0,0 +1,35 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Exception;
+
+/**
+ * Ignite client general exception.
+ */
+class ClientException extends \Exception
+{
+ /**
+ * Constructs a ClientException with the specified detail message.
+ *
+ * @param string $message the detail message.
+ */
+ public function __construct(string $message)
+ {
+ parent::__construct($message);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Exception/NoConnectionException.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Exception/NoConnectionException.php b/modules/platforms/php/src/Apache/Ignite/Exception/NoConnectionException.php
new file mode 100644
index 0000000..04a7580
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Exception/NoConnectionException.php
@@ -0,0 +1,35 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Exception;
+
+/**
+ * Ignite client is not connected.
+ */
+class NoConnectionException extends ClientException
+{
+ /**
+ * Constructs a NoConnectionException with the specified detail message.
+ *
+ * @param string $message the detail message.
+ */
+ public function __construct(string $message = null)
+ {
+ parent::__construct($message ? $message : 'Operation is not completed due to the connection problem');
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Exception/OperationException.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Exception/OperationException.php b/modules/platforms/php/src/Apache/Ignite/Exception/OperationException.php
new file mode 100644
index 0000000..49862e7
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Exception/OperationException.php
@@ -0,0 +1,35 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Exception;
+
+/**
+ * Ignite server returns error for the requested operation.
+ */
+class OperationException extends ClientException
+{
+ /**
+ * Constructs an OperationException with the specified detail message.
+ *
+ * @param string $message the detail message.
+ */
+ public function __construct(string $message)
+ {
+ parent::__construct($message);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Exception/OperationStatusUnknownException.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Exception/OperationStatusUnknownException.php b/modules/platforms/php/src/Apache/Ignite/Exception/OperationStatusUnknownException.php
new file mode 100644
index 0000000..74aab6d
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Exception/OperationStatusUnknownException.php
@@ -0,0 +1,35 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Exception;
+
+/**
+ * Status of the requested operation is unknown (eg. due to a connection problem during the operation).
+ */
+class OperationStatusUnknownException extends ClientException
+{
+ /**
+ * Constructs an OperationStatusUnknownException with the specified detail message.
+ *
+ * @param string $message the detail message.
+ */
+ public function __construct(string $message)
+ {
+ parent::__construct($message);
+ }
+}