From 82bbb6f81d38723204aec7df53d764fac390d5d8 Mon Sep 17 00:00:00 2001 From: Paul Dix Date: Fri, 8 Nov 2013 08:10:41 -0800 Subject: [PATCH 01/72] Initial commit --- LICENSE | 20 ++++++++++++++++++++ README.md | 2 ++ 2 files changed, 22 insertions(+) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..38ee24919 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 InfluxDB + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 000000000..7483497be --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +influxdb-php +============ From 93ed0316363a7e4ff875b234964461c55654b60d Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Tue, 16 Jun 2015 22:31:13 +0200 Subject: [PATCH 02/72] Intitial commit --- .gitignore | 4 + composer.json | 28 ++++ composer.lock | 240 ++++++++++++++++++++++++++++ src/Leaseweb/InfluxDB/Client.php | 37 +++++ src/Leaseweb/InfluxDB/ResultSet.php | 25 +++ test.php | 10 ++ 6 files changed, 344 insertions(+) create mode 100644 .gitignore create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 src/Leaseweb/InfluxDB/Client.php create mode 100644 src/Leaseweb/InfluxDB/ResultSet.php create mode 100644 test.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..41f1fd93f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# Created by .gitignore support plugin (hsz.mobi) + +vendor/ +.idea \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 000000000..a70a560bd --- /dev/null +++ b/composer.json @@ -0,0 +1,28 @@ +{ + "name": "leaseweb/php-influxdb", + "description": "InfluxDB client library for PHP", + "minimum-stability": "dev", + "authors": [ + { + "name": "Stephen Hoogendijk", + "email": "stephen@tca0.nl" + } + ], + "require": { + "php": ">=5.4", + "guzzlehttp/guzzle": "~6.0" + }, + "scripts": { + "post-install-cmd": [ + + ], + "post-update-cmd": [ + + ] + }, + "autoload": { + "psr-4" : { + "Leaseweb\\InfluxDB": "src/Leaseweb/InfluxDB" + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 000000000..7710aa242 --- /dev/null +++ b/composer.lock @@ -0,0 +1,240 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "6ef9eaeaea0251d4dc34987cf21167b4", + "packages": [ + { + "name": "guzzlehttp/guzzle", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "0da18ca6654b98a1d57cc9278331a7f7491d0d04" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/0da18ca6654b98a1d57cc9278331a7f7491d0d04", + "reference": "0da18ca6654b98a1d57cc9278331a7f7491d0d04", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "~1.0", + "guzzlehttp/psr7": "~1.0", + "php": ">=5.5.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0", + "psr/log": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2015-06-14 02:43:56" + }, + { + "name": "guzzlehttp/promises", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "156f6915a89ca2cc9a3b36abef65f336ce68c754" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/156f6915a89ca2cc9a3b36abef65f336ce68c754", + "reference": "156f6915a89ca2cc9a3b36abef65f336ce68c754", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2015-06-16 01:16:05" + }, + { + "name": "guzzlehttp/psr7", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "644db73bfa1571af785172887836d6ec01d787ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/644db73bfa1571af785172887836d6ec01d787ed", + "reference": "644db73bfa1571af785172887836d6ec01d787ed", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "PSR-7 message implementation", + "keywords": [ + "http", + "message", + "stream", + "uri" + ], + "time": "2015-06-16 01:05:58" + }, + { + "name": "psr/http-message", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2015-05-04 20:22:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.4" + }, + "platform-dev": [] +} diff --git a/src/Leaseweb/InfluxDB/Client.php b/src/Leaseweb/InfluxDB/Client.php new file mode 100644 index 000000000..180bfffa9 --- /dev/null +++ b/src/Leaseweb/InfluxDB/Client.php @@ -0,0 +1,37 @@ + Date: Tue, 16 Jun 2015 22:36:57 +0200 Subject: [PATCH 03/72] Added license and readme files --- LICENSE.md | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 19 +++++ 2 files changed, 220 insertions(+) create mode 100644 LICENSE.md create mode 100644 README.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..27f048ee6 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2015 LeaseWeb Technologies B.V. + + Licensed 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. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..69a09f65f --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# php-influxdb - InfluxDB client library for PHP + +##Overview + +This library was created to have php port of the python influxdb client. +This way there will be a common abstraction library between different programming languages. + +##Usage + +Initialize a new client object: + +```php + +$client = new Leaseweb\InfluxDB\Client($host, $port); + + +``` + +This will create a new client object which you can use to read and write points to InfluxDB. From acf84298e6ebe865c8c3f2542ce6ecbce25d4042 Mon Sep 17 00:00:00 2001 From: Sean Beckett Date: Tue, 16 Jun 2015 17:09:20 -0700 Subject: [PATCH 04/72] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7483497be..9d61bb165 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ influxdb-php ============ +This is a placeholder. We encourage you to submit a pull request if you have a contribution From 0986f43bdd7964e3f79051eb49ab1e2371f27332 Mon Sep 17 00:00:00 2001 From: Daniel Martinez Date: Wed, 17 Jun 2015 15:35:42 +0200 Subject: [PATCH 05/72] Adding unit tests --- .gitignore | 3 ++- composer.json | 7 ++++++- phpunit.xml | 29 +++++++++++++++++++++++++++++ tests/unit/ResultSetTest.php | 12 ++++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 phpunit.xml create mode 100644 tests/unit/ResultSetTest.php diff --git a/.gitignore b/.gitignore index 41f1fd93f..133f00587 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # Created by .gitignore support plugin (hsz.mobi) vendor/ -.idea \ No newline at end of file +.idea +build/ diff --git a/composer.json b/composer.json index a70a560bd..eebde4a54 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,12 @@ }, "autoload": { "psr-4" : { - "Leaseweb\\InfluxDB": "src/Leaseweb/InfluxDB" + "Leaseweb\\InfluxDB\\": "src/Leaseweb/InfluxDB" + } + }, + "autoload-dev": { + "psr-4": { + "Leaseweb\\InfluxDB\\Test\\": "tests" } } } diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 000000000..102011e1c --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,29 @@ + + + + + tests + + + + + src/ + + + + + + + + + + diff --git a/tests/unit/ResultSetTest.php b/tests/unit/ResultSetTest.php new file mode 100644 index 000000000..2634a01ff --- /dev/null +++ b/tests/unit/ResultSetTest.php @@ -0,0 +1,12 @@ +assertTrue( + false + ); + } +} \ No newline at end of file From d6dc5d50621c775260e483d7da4257370f79b683 Mon Sep 17 00:00:00 2001 From: Daniel Martinez Date: Wed, 17 Jun 2015 16:03:21 +0200 Subject: [PATCH 06/72] ResultSet - implementing getPoints --- src/Leaseweb/InfluxDB/ResultSet.php | 39 +++++++++++++++---- tests/unit/ResultSetTest.php | 19 +++++++++- tests/unit/result.example.json | 59 +++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 tests/unit/result.example.json diff --git a/src/Leaseweb/InfluxDB/ResultSet.php b/src/Leaseweb/InfluxDB/ResultSet.php index 9311314e9..7cde9dd16 100644 --- a/src/Leaseweb/InfluxDB/ResultSet.php +++ b/src/Leaseweb/InfluxDB/ResultSet.php @@ -5,7 +5,11 @@ namespace Leaseweb\InfluxDB; - +/** + * Class ResultSet + * + * @package Leaseweb\InfluxDB + */ class ResultSet { /** @@ -13,13 +17,32 @@ class ResultSet */ protected $raw = ''; - /** - * @param $raw - * - * @param bool $throwExceptions - */ - public function __construct($raw, $throwExceptions = true) - { + protected $parsedResults = array(); + /** + * @param $raw + * + * @throws \InvalidArgumentException + */ + public function __construct($raw) + { + $this->raw = $raw; + + $this->parsedResults = json_decode($raw, true); + + if (json_last_error() !== JSON_ERROR_NONE) { + throw new \InvalidArgumentException("Invalid JSON"); + } + } + + /** + * @param $metricName + * @param array $tags + * + * @return array $points + */ + public function getPoints($metricName = '', $tags = array()) + { + return array(); } } \ No newline at end of file diff --git a/tests/unit/ResultSetTest.php b/tests/unit/ResultSetTest.php index 2634a01ff..1f6016fdd 100644 --- a/tests/unit/ResultSetTest.php +++ b/tests/unit/ResultSetTest.php @@ -1,12 +1,27 @@ resultSet = new ResultSet($resultJsonExample); + } + + public function testGetPointsFromMeasurementName() + { + $measurementName = 'cpu_load_short'; + + $points = $this->resultSet->getPoints($measurementName); + $this->assertTrue( - false + is_array($points) ); } } \ No newline at end of file diff --git a/tests/unit/result.example.json b/tests/unit/result.example.json new file mode 100644 index 000000000..948d39662 --- /dev/null +++ b/tests/unit/result.example.json @@ -0,0 +1,59 @@ +{ + "results": [ + { + "series": [ + { + "measurement": "cpu_load_short", + "tags": { + "host": "server01", + "region": "us-west" + }, + "columns": [ + "time", + "value" + ], + "values": [ + [ + "2015-01-29T21:51:28.968422294Z", + 0.64 + ] + ] + }, + { + "measurement": "cpu_load_short", + "tags": { + "host": "server02", + "region": "us-west" + }, + "columns": [ + "time", + "value" + ], + "values": [ + [ + "2015-01-29T21:51:28.968422294Z", + 0.65 + ] + ] + }, + { + "measurement": "other_serie", + "tags": { + "host": "server01", + "region": "us-west" + }, + "columns": [ + "time", + "value" + ], + "values": [ + [ + "2015-01-29T21:51:28.968422294Z", + 0.66 + ] + ] + } + ] + } + ] +} \ No newline at end of file From 413cbf6eb2d5f6b007df073780ee03a6ebb021f2 Mon Sep 17 00:00:00 2001 From: Daniel Martinez Date: Thu, 18 Jun 2015 10:11:19 +0200 Subject: [PATCH 07/72] Testing ResultSet --- src/Leaseweb/InfluxDB/ResultSet.php | 29 ++++++++++++++++++++++++-- tests/unit/ResultSetTest.php | 32 +++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/Leaseweb/InfluxDB/ResultSet.php b/src/Leaseweb/InfluxDB/ResultSet.php index 7cde9dd16..0e92dc6b8 100644 --- a/src/Leaseweb/InfluxDB/ResultSet.php +++ b/src/Leaseweb/InfluxDB/ResultSet.php @@ -41,8 +41,33 @@ class ResultSet * * @return array $points */ - public function getPoints($metricName = '', $tags = array()) + public function getPoints($metricName = '', array $tags = array()) { - return array(); + $points = array(); + + // todo: we are considering always have a metricName + foreach ($this->parsedResults['results'] as $result) { + + foreach ($result['series'] as $serie) { + if ($serie['measurement'] == $metricName) { + + $points[] = $this->getPointsFromSerie($serie); + } + } + } + + return $points; + } + + /** + * @param array $serie + * @return array + */ + private function getPointsFromSerie(array $serie) + { + return array_combine( + $serie['columns'], + array_shift($serie['values']) + ); } } \ No newline at end of file diff --git a/tests/unit/ResultSetTest.php b/tests/unit/ResultSetTest.php index 1f6016fdd..18a86de4c 100644 --- a/tests/unit/ResultSetTest.php +++ b/tests/unit/ResultSetTest.php @@ -14,14 +14,46 @@ class ResultSetTest extends \PHPUnit_Framework_TestCase $this->resultSet = new ResultSet($resultJsonExample); } + /** + * @expectedException \InvalidArgumentException + */ + public function testThrowsExceptionIfJSONisNotValid() + { + $invalidJSON = 'foo'; + + new ResultSet($invalidJSON); + } + + /** + * We can get points for a measurement + */ public function testGetPointsFromMeasurementName() { $measurementName = 'cpu_load_short'; + $expectedNumberOfPoints = 2; + $expectedValueFromFirstPoint = 0.64; $points = $this->resultSet->getPoints($measurementName); $this->assertTrue( is_array($points) ); + + $this->assertCount($expectedNumberOfPoints, $points); + + $somePoint = array_shift($points); + + $this->assertEquals($expectedValueFromFirstPoint, $somePoint['value']); + } + + public function testGetPointsFromTags() + { + $tags = array("host" => "server01"); + + $points = $this->resultSet->getPoints('', $tags); + + $this->assertTrue( + is_array($points) + ); } } \ No newline at end of file From 016c5abc6ef986e9ad671e3d42a3ea3903644368 Mon Sep 17 00:00:00 2001 From: Daniel Martinez Date: Thu, 18 Jun 2015 13:40:16 +0200 Subject: [PATCH 08/72] ResultSet - getSeries --- src/Leaseweb/InfluxDB/InfluxDBClientError.php | 12 ++++ src/Leaseweb/InfluxDB/ResultSet.php | 55 +++++++++++++++---- tests/unit/ResultSetTest.php | 19 +++++-- 3 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 src/Leaseweb/InfluxDB/InfluxDBClientError.php diff --git a/src/Leaseweb/InfluxDB/InfluxDBClientError.php b/src/Leaseweb/InfluxDB/InfluxDBClientError.php new file mode 100644 index 000000000..75b8dbc22 --- /dev/null +++ b/src/Leaseweb/InfluxDB/InfluxDBClientError.php @@ -0,0 +1,12 @@ +parsedResults['error'])) { + throw new InfluxDBClientError($this->parsedResults['error']); + } } /** @@ -45,29 +54,51 @@ class ResultSet { $points = array(); - // todo: we are considering always have a metricName - foreach ($this->parsedResults['results'] as $result) { - - foreach ($result['series'] as $serie) { - if ($serie['measurement'] == $metricName) { - - $points[] = $this->getPointsFromSerie($serie); - } + foreach ($this->getSeries() as $serie) { + if ($serie['measurement'] == $metricName || array_intersect($tags, $serie['tags'])) { + $points = array_merge($points, $this->getPointsFromSerie($serie)); } } return $points; } + /** + * @see: https://influxdb.com/docs/v0.9/concepts/reading_and_writing_data.html + * + * results is an array of objects, one for each query, + * each containing the keys for a series + * + * @return array $series + */ + private function getSeries() + { + $pickSeries = function ($object) { + return $object['series']; + }; + + // Foreach object, pick series key + return array_shift( + array_map($pickSeries, $this->parsedResults['results']) + ); + } + /** * @param array $serie * @return array */ private function getPointsFromSerie(array $serie) { - return array_combine( - $serie['columns'], - array_shift($serie['values']) - ); + $points = array(); + + foreach ($serie['values'] as $point) { + $points[] = array_combine( + $serie['columns'], + $point + ); + } + + return $points; } + } \ No newline at end of file diff --git a/tests/unit/ResultSetTest.php b/tests/unit/ResultSetTest.php index 18a86de4c..82c50b526 100644 --- a/tests/unit/ResultSetTest.php +++ b/tests/unit/ResultSetTest.php @@ -25,7 +25,7 @@ class ResultSetTest extends \PHPUnit_Framework_TestCase } /** - * We can get points for a measurement + * We can get points from measurement */ public function testGetPointsFromMeasurementName() { @@ -49,11 +49,22 @@ class ResultSetTest extends \PHPUnit_Framework_TestCase public function testGetPointsFromTags() { $tags = array("host" => "server01"); + $expectedNumberOfPoints = 2; $points = $this->resultSet->getPoints('', $tags); - $this->assertTrue( - is_array($points) - ); + $this->assertTrue(is_array($points)); + $this->assertCount($expectedNumberOfPoints, $points); + } + + public function testGetPointsFromNameAndTags() + { + $tags = array("host" => "server01"); + $expectedNumberOfPoints = 2; + + $points = $this->resultSet->getPoints('', $tags); + + $this->assertTrue(is_array($points)); + $this->assertCount($expectedNumberOfPoints, $points); } } \ No newline at end of file From 87121d212640cabe904c3bc60ec93ebee9715171 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 18 Jun 2015 13:52:50 +0200 Subject: [PATCH 09/72] Intermediate commit; added querybuilder; retention policy object --- README.md | 7 +- composer.json | 4 +- composer.lock | 4 +- src/Leaseweb/InfluxDB/Client.php | 150 +++++++++++- src/Leaseweb/InfluxDB/Database.php | 96 ++++++++ .../InfluxDB/Database/RetentionPolicy.php | 44 ++++ src/Leaseweb/InfluxDB/Exception.php | 12 + src/Leaseweb/InfluxDB/Query/Builder.php | 228 ++++++++++++++++++ test.php | 10 - 9 files changed, 531 insertions(+), 24 deletions(-) create mode 100644 src/Leaseweb/InfluxDB/Database.php create mode 100644 src/Leaseweb/InfluxDB/Database/RetentionPolicy.php create mode 100644 src/Leaseweb/InfluxDB/Exception.php create mode 100644 src/Leaseweb/InfluxDB/Query/Builder.php delete mode 100644 test.php diff --git a/README.md b/README.md index 69a09f65f..600553ba6 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ -# php-influxdb - InfluxDB client library for PHP +# influxdb-php +## InfluxDB client library for PHP -##Overview +###Overview This library was created to have php port of the python influxdb client. This way there will be a common abstraction library between different programming languages. -##Usage +###Usage Initialize a new client object: diff --git a/composer.json b/composer.json index eebde4a54..5308120ac 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "leaseweb/php-influxdb", + "name": "leaseweb/influxdb-php", "description": "InfluxDB client library for PHP", "minimum-stability": "dev", "authors": [ @@ -9,7 +9,7 @@ } ], "require": { - "php": ">=5.4", + "php": ">=5.3", "guzzlehttp/guzzle": "~6.0" }, "scripts": { diff --git a/composer.lock b/composer.lock index 7710aa242..0613c1ffe 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "6ef9eaeaea0251d4dc34987cf21167b4", + "hash": "d4cd96b7a6d552bb16ed5847dd32d4e3", "packages": [ { "name": "guzzlehttp/guzzle", @@ -234,7 +234,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.4" + "php": ">=5.3" }, "platform-dev": [] } diff --git a/src/Leaseweb/InfluxDB/Client.php b/src/Leaseweb/InfluxDB/Client.php index 180bfffa9..7854e10aa 100644 --- a/src/Leaseweb/InfluxDB/Client.php +++ b/src/Leaseweb/InfluxDB/Client.php @@ -5,9 +5,68 @@ namespace Leaseweb\InfluxDB; - +/** + * Class Client + * + * @package Leaseweb\InfluxDB + */ class Client { + /** + * @var string + */ + protected $host = ''; + + /** + * @var int + */ + protected $port = 8086; + + /** + * @var string + */ + protected $username = ''; + + /** + * @var string + */ + protected $password = ''; + + /** + * @var string + */ + protected $database = ''; + + /** + * @var int + */ + protected $timeout = 0; + + /** + * @var bool + */ + protected $scheme = 'http'; + + /** + * @var bool + */ + protected $verifySSL = false; + + /** + * @var bool + */ + protected $useUdp = false; + + /** + * @var int + */ + protected $udpPort = 4444; + + + /** + * @var + */ + protected $baseURI; /** * @param string $host @@ -18,20 +77,97 @@ class Client * @param bool $ssl * @param bool $verifySSL * @param int $timeout - * @param bool $useUdp - * @param int $udpPort + * + * @todo add UDP support + * @todo add SSL support */ - public function __construct($host, + public function __construct( + $host, $port = 8086, $username = '', $password = '', $database = '', $ssl = false, $verifySSL = false, - $timeout = 0, - $useUdp = false, - $udpPort = 4444) + $timeout = 0 +// $useUdp = false, +// $udpPort = 4444 + ) { + $this->host = $host; + $this->port = (int) $port; + $this->username = $username; + $this->password = $password; + $this->database = $database; + $this->timeout = $timeout; + $this->verifySSL = (bool) $verifySSL; + + if ($ssl) { + $this->scheme = 'https'; + } + + // the the base URI + $this->setBaseURI(sprintf('%s://%s:%d', $this->scheme, $this->host, $this->port)); + + $return = null; + + // return a database instance if a database name has been given + if ($this->database) { + $return = $this->db($database); + } + + return $return; + + } + + /** + * Use the given database + * + * @param string $name + * + * @return Database + */ + public function db($name) + { + + if (empty($name)) { + throw new \InvalidArgumentException(sprintf('No database provided')); + } + + return new Database($name, $this); + } + + /** + * Build the client from a dsn + * + * Example: tcp+influxdb://username:pass@localhost:8086/databasename', timeout=5 + * + * @param string $dsn + * + * @todo finish this functionality + */ + public static function fromDSN($dsn) + { + $args = array(); + + + + } + + /** + * @return mixed + */ + public function getBaseURI() + { + return $this->baseURI; + } + + /** + * @param mixed $baseURI + */ + public function setBaseURI($baseURI) + { + $this->baseURI = $baseURI; } } \ No newline at end of file diff --git a/src/Leaseweb/InfluxDB/Database.php b/src/Leaseweb/InfluxDB/Database.php new file mode 100644 index 000000000..f62f3bdcc --- /dev/null +++ b/src/Leaseweb/InfluxDB/Database.php @@ -0,0 +1,96 @@ +client = $client; + + $this->httpClient = new Client(array('base_uri' => $this->client->getBaseURI())); + } + + /** + * Query influxDB + * + * @param string $query + * @param array $params + */ + public function query($query, $params = array()) + { + $params = array_merge(array('q' => $query, $params)); + + $result = $this->httpClient->get('query', $params); + + die(var_dump($result)); + } + + /** + * Create this database + * + * @param RetentionPolicy $retentionPolicy + */ + public function create(RetentionPolicy $retentionPolicy) + { + return $this->query(sprintf('CREATE DATABASE %s', $this->name)); + } + + /** + * Drop this database + */ + public function drop() + { + + } + + /** + * Retrieve the query builder + * + * @return QueryBuilder + */ + public function getQueryBuilder() + { + return new QueryBuilder($this); + } + + +} \ No newline at end of file diff --git a/src/Leaseweb/InfluxDB/Database/RetentionPolicy.php b/src/Leaseweb/InfluxDB/Database/RetentionPolicy.php new file mode 100644 index 000000000..6549f809f --- /dev/null +++ b/src/Leaseweb/InfluxDB/Database/RetentionPolicy.php @@ -0,0 +1,44 @@ +name = $name; + $this->duration = $duration; + $this->replication = $replication; + $this->default = $default; + } +} \ No newline at end of file diff --git a/src/Leaseweb/InfluxDB/Exception.php b/src/Leaseweb/InfluxDB/Exception.php new file mode 100644 index 000000000..c8f674344 --- /dev/null +++ b/src/Leaseweb/InfluxDB/Exception.php @@ -0,0 +1,12 @@ + + */ + +namespace Leaseweb\InfluxDB\Query; + +use Leaseweb\InfluxDB\Database; + +/** + * Class QueryBuilder + * + * Abstraction class for getting time series out of InfluxDB + * + * Sample usage: + * + * $series = new QueryBuilder($db); + * $series->percentile(95)->setTimeRange($timeFrom, $timeTo)->getResult(); + * + * $series->select('*')->from('*')->getResult(); + * + * @package Leaseweb\InfluxDB + */ +class Builder +{ + + protected $db = null; + protected $selection = '*'; + protected $where = array(); + protected $startTime = null; + protected $endTime = null; + protected $metric = null; + + /** + * @param Database $db + */ + public function __construct(Database $db) + { + $this->db = $db; + } + + /** + * @param string $metric The metric to select (required) + * + * @return $this + */ + public function from($metric) + { + $this->metric = $metric; + + return $this; + } + + /** + * Custom select method + * + * example: + * + * $series->select('sum(value)', + * + * @param string $customSelect + * + * @return $this + */ + public function select($customSelect) + { + $this->selection = $customSelect; + + return $this; + } + + /** + * @param array $conditions + * + * Example: array('time > now()', 'time < now() -1d'); + * + * @return $this + */ + public function where(array $conditions) + { + + foreach ($conditions as $condition) { + $this->where[] = $condition; + } + + return $this; + } + + /** + * @return $this + */ + public function selectAll() + { + $this->selection = '*'; + + return $this; + } + + /** + * @param string $field + * + * @return $this + */ + public function count($field = 'type') + { + $this->selection = sprintf('count(%s)', $field); + + return $this; + } + + /** + * @param string $field + * + * @return $this + */ + public function mean($field = 'type') + { + $this->selection = sprintf('mean(%s)', $field); + + return $this; + } + + /** + * @param string $field + * + * @return $this + */ + public function sum($field = 'type') + { + $this->selection = sprintf('sum(%s)', $field); + + return $this; + } + + /** + * @param string $field + * + * @return $this + */ + public function first($field = 'type') + { + $this->selection = sprintf('first(%s)', $field); + + return $this; + } + + /** + * @param string $field + * + * @return $this + */ + public function last($field = 'type') + { + $this->selection = sprintf('first(%s)', $field); + + return $this; + } + + /** + * Set's the time range to select data from + * + * @param int $from Unix timestamp from + * @param int $to Unix timestamp to + * + * @return $this + */ + public function setTimeRange($from, $to) + { + $fromDate = date('Y-m-d H:i:s', $from); + $toDate = date('Y-m-d H:i:s', $to); + + $this->where(array("time > '$fromDate'", "time < '$toDate'")); + + return $this; + } + + /** + * @param int $percentile Percentage to select (for example 95 for 95th percentile billing) + * + * @return $this + */ + public function percentile($percentile = 95) + { + $this->selection = sprintf('percentile(value, %d)', (int) $percentile); + + return $this; + } + + /** + * Gets the result from the database (builds the query) + * + * @param bool $raw always return the ResultSeriesObjects, even when using an aggregation function + * + * @return array|null + */ + public function getResult($raw = false) + { + $query = sprintf("SELECT %s FROM %s", $this->selection, $this->metric); + $aggregateKey = null; + + if (!$this->metric) { + throw new \InvalidArgumentException('No metric provided to from()'); + } + + if (preg_match("/([a-z]+)\(/i", $this->selection, $matches)) { + $aggregateKey = $matches[1]; + } + + for ($i=0; $i < count($this->where); $i++) { + $selection = 'WHERE'; + if ($i > 0) { + $selection = 'AND'; + } + + $clause = $this->where[$i]; + $query .= ' ' . $selection . ' ' . $clause; + + } + + $queryResult = $this->db->query($query); + + if ($queryResult && $aggregateKey && !$raw) { + return (float) $queryResult[0]->$aggregateKey; + } + + return $queryResult; + } +} \ No newline at end of file diff --git a/test.php b/test.php deleted file mode 100644 index e8efd10e5..000000000 --- a/test.php +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/php - - Date: Thu, 18 Jun 2015 14:21:30 +0200 Subject: [PATCH 10/72] Changing measurement to name in result set --- src/Leaseweb/InfluxDB/ResultSet.php | 2 +- tests/unit/ResultSetTest.php | 16 ++++++++++++++++ tests/unit/result.example.json | 6 +++--- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Leaseweb/InfluxDB/ResultSet.php b/src/Leaseweb/InfluxDB/ResultSet.php index dd9b91f1f..360151d9a 100644 --- a/src/Leaseweb/InfluxDB/ResultSet.php +++ b/src/Leaseweb/InfluxDB/ResultSet.php @@ -55,7 +55,7 @@ class ResultSet $points = array(); foreach ($this->getSeries() as $serie) { - if ($serie['measurement'] == $metricName || array_intersect($tags, $serie['tags'])) { + if ($serie['name'] == $metricName || array_intersect($tags, $serie['tags'])) { $points = array_merge($points, $this->getPointsFromSerie($serie)); } } diff --git a/tests/unit/ResultSetTest.php b/tests/unit/ResultSetTest.php index 82c50b526..a7a2a170d 100644 --- a/tests/unit/ResultSetTest.php +++ b/tests/unit/ResultSetTest.php @@ -24,6 +24,22 @@ class ResultSetTest extends \PHPUnit_Framework_TestCase new ResultSet($invalidJSON); } + /** + * Throws Exception if something went wrong with influxDB + * @expectedException \Leaseweb\InfluxDB\InfluxDBClientError + */ + public function testThrowsInfluxDBException() + { + + $errorResult = << Date: Thu, 18 Jun 2015 14:59:00 +0200 Subject: [PATCH 11/72] ResultSet::getPoints empty parameters --- src/Leaseweb/InfluxDB/ResultSet.php | 10 +++++++--- tests/unit/ClientTest.php | 20 ++++++++++++++++++++ tests/unit/ResultSetTest.php | 17 +++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 tests/unit/ClientTest.php diff --git a/src/Leaseweb/InfluxDB/ResultSet.php b/src/Leaseweb/InfluxDB/ResultSet.php index 360151d9a..fedcbe3be 100644 --- a/src/Leaseweb/InfluxDB/ResultSet.php +++ b/src/Leaseweb/InfluxDB/ResultSet.php @@ -55,7 +55,11 @@ class ResultSet $points = array(); foreach ($this->getSeries() as $serie) { - if ($serie['name'] == $metricName || array_intersect($tags, $serie['tags'])) { + + if ((empty($metricName) && empty($tags)) + || $serie['name'] == $metricName + || array_intersect($tags, $serie['tags']) + ) { $points = array_merge($points, $this->getPointsFromSerie($serie)); } } @@ -68,10 +72,10 @@ class ResultSet * * results is an array of objects, one for each query, * each containing the keys for a series - * + * * @return array $series */ - private function getSeries() + public function getSeries() { $pickSeries = function ($object) { return $object['series']; diff --git a/tests/unit/ClientTest.php b/tests/unit/ClientTest.php new file mode 100644 index 000000000..4485be7e6 --- /dev/null +++ b/tests/unit/ClientTest.php @@ -0,0 +1,20 @@ +assertTrue( + true + ); + } +} \ No newline at end of file diff --git a/tests/unit/ResultSetTest.php b/tests/unit/ResultSetTest.php index a7a2a170d..0d0aee18c 100644 --- a/tests/unit/ResultSetTest.php +++ b/tests/unit/ResultSetTest.php @@ -40,6 +40,23 @@ EOD; new ResultSet($errorResult); } + /** + * We can get points from measurement + */ + public function testGetPoints() + { + $expectedNumberOfPoints = 3; + + $points = $this->resultSet->getPoints(); + + $this->assertTrue( + is_array($points) + ); + + $this->assertCount($expectedNumberOfPoints, $points); + + } + /** * We can get points from measurement */ From d55af50722c66950c5022bf3d28383ef680603f3 Mon Sep 17 00:00:00 2001 From: danibrutal Date: Thu, 18 Jun 2015 15:05:04 +0200 Subject: [PATCH 12/72] Throws InfluxDBClientError if there was an error after quering --- src/Leaseweb/InfluxDB/ResultSet.php | 7 +++++++ tests/unit/ResultSetTest.php | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/Leaseweb/InfluxDB/ResultSet.php b/src/Leaseweb/InfluxDB/ResultSet.php index fedcbe3be..6a5a1deb8 100644 --- a/src/Leaseweb/InfluxDB/ResultSet.php +++ b/src/Leaseweb/InfluxDB/ResultSet.php @@ -73,11 +73,18 @@ class ResultSet * results is an array of objects, one for each query, * each containing the keys for a series * + * @throws InfluxDBClientError + * * @return array $series */ public function getSeries() { $pickSeries = function ($object) { + + if (isset($object['error'])) { + throw new InfluxDBClientError($object['error']); + } + return $object['series']; }; diff --git a/tests/unit/ResultSetTest.php b/tests/unit/ResultSetTest.php index 0d0aee18c..ce1471d10 100644 --- a/tests/unit/ResultSetTest.php +++ b/tests/unit/ResultSetTest.php @@ -40,6 +40,27 @@ EOD; new ResultSet($errorResult); } + /** + * Throws Exception if something went wrong with influxDB after processing the query + * @expectedException \Leaseweb\InfluxDB\InfluxDBClientError + */ + public function testThrowsInfluxDBExceptionIfAnyErrorInSeries() + { + + $errorResult = <<getSeries(); + } + /** * We can get points from measurement */ From 72cd8b82bde79d7e11be577b7fc60c2fb433a283 Mon Sep 17 00:00:00 2001 From: danibrutal Date: Thu, 18 Jun 2015 15:37:41 +0200 Subject: [PATCH 13/72] Throws Exception in constructor for error in first serie --- src/Leaseweb/InfluxDB/ResultSet.php | 6 +++++- tests/unit/ResultSetTest.php | 3 +-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Leaseweb/InfluxDB/ResultSet.php b/src/Leaseweb/InfluxDB/ResultSet.php index 6a5a1deb8..f9c932b91 100644 --- a/src/Leaseweb/InfluxDB/ResultSet.php +++ b/src/Leaseweb/InfluxDB/ResultSet.php @@ -41,6 +41,10 @@ class ResultSet // There was an error in the query thrown by influxdb if (isset($this->parsedResults['error'])) { throw new InfluxDBClientError($this->parsedResults['error']); + + // Check if there are errors in the first serie + } elseif (isset($this->parsedResults['results'][0]['error'])) { + throw new InfluxDBClientError($this->parsedResults['results'][0]['error']); } } @@ -80,7 +84,7 @@ class ResultSet public function getSeries() { $pickSeries = function ($object) { - + if (isset($object['error'])) { throw new InfluxDBClientError($object['error']); } diff --git a/tests/unit/ResultSetTest.php b/tests/unit/ResultSetTest.php index ce1471d10..024da364f 100644 --- a/tests/unit/ResultSetTest.php +++ b/tests/unit/ResultSetTest.php @@ -57,8 +57,7 @@ EOD; ] } EOD; - $rs = new ResultSet($errorResult); - $rs->getSeries(); + new ResultSet($errorResult); } /** From 43c89a161d6c49336ae7ef22bbb499c7224a8fe7 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 18 Jun 2015 16:17:57 +0200 Subject: [PATCH 14/72] Added list methods, cleaned up API --- .gitignore | 1 + src/Leaseweb/InfluxDB/Client.php | 98 ++++++++++++++----- src/Leaseweb/InfluxDB/Database.php | 94 +++++++++++++++--- src/Leaseweb/InfluxDB/Database/Exception.php | 12 +++ .../InfluxDB/Database/RetentionPolicy.php | 21 ++-- src/Leaseweb/InfluxDB/Query/Builder.php | 17 ++-- src/Leaseweb/InfluxDB/Query/Exception.php | 12 +++ 7 files changed, 199 insertions(+), 56 deletions(-) create mode 100644 src/Leaseweb/InfluxDB/Database/Exception.php create mode 100644 src/Leaseweb/InfluxDB/Query/Exception.php diff --git a/.gitignore b/.gitignore index 133f00587..2826a22d7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ vendor/ .idea build/ +test.php \ No newline at end of file diff --git a/src/Leaseweb/InfluxDB/Client.php b/src/Leaseweb/InfluxDB/Client.php index 7854e10aa..38125bcc2 100644 --- a/src/Leaseweb/InfluxDB/Client.php +++ b/src/Leaseweb/InfluxDB/Client.php @@ -5,6 +5,8 @@ namespace Leaseweb\InfluxDB; + +use GuzzleHttp\Client as httpClient; /** * Class Client * @@ -32,11 +34,6 @@ class Client */ protected $password = ''; - /** - * @var string - */ - protected $database = ''; - /** * @var int */ @@ -62,18 +59,21 @@ class Client */ protected $udpPort = 4444; - /** * @var */ protected $baseURI; + /** + * @var \GuzzleHttp\Client + */ + protected $httpClient; + /** * @param string $host * @param int $port * @param string $username * @param string $password - * @param string $database * @param bool $ssl * @param bool $verifySSL * @param int $timeout @@ -86,7 +86,6 @@ class Client $port = 8086, $username = '', $password = '', - $database = '', $ssl = false, $verifySSL = false, $timeout = 0 @@ -99,7 +98,6 @@ class Client $this->port = (int) $port; $this->username = $username; $this->password = $password; - $this->database = $database; $this->timeout = $timeout; $this->verifySSL = (bool) $verifySSL; @@ -110,15 +108,11 @@ class Client // the the base URI $this->setBaseURI(sprintf('%s://%s:%d', $this->scheme, $this->host, $this->port)); - $return = null; - - // return a database instance if a database name has been given - if ($this->database) { - $return = $this->db($database); - } - - return $return; - + $this->httpClient = new httpClient(array( + 'base_uri' => $this->getBaseURI(), + 'timeout' => $this->getTimeout() + ) + ); } /** @@ -132,12 +126,59 @@ class Client { if (empty($name)) { - throw new \InvalidArgumentException(sprintf('No database provided')); + throw new \InvalidArgumentException(sprintf('No name provided')); } return new Database($name, $this); } + /** + * Query influxDB + * + * @param string $database + * @param string $query + * @param array $params + * + * @return ResultSet + * @throws Exception + */ + public function query($database = null, $query, $params = array()) + { + + if ($database) { + $params += array('db' => $database); + } + + $params = array_merge(array('q' => $query), $params); + + try { + $response = $this->httpClient->get('query', array('query' => $params, 'http_errors' => false)); + + $raw = (string) $response->getBody(); + + return new ResultSet($raw); + + } catch (\Exception $e) { + throw new Exception(sprintf('Query has failed, exception: %s', $e->getMessage())); + } + } + + /** + * List all the databases + */ + public function listDatabases() + { + $result = $this->query(null, 'SHOW DATABASES')->getPoints(); + + $names = array(); + + foreach ($result as $item) { + $names[] = $item['name']; + } + + return $names; + } + /** * Build the client from a dsn * @@ -150,9 +191,6 @@ class Client public static function fromDSN($dsn) { $args = array(); - - - } /** @@ -170,4 +208,20 @@ class Client { $this->baseURI = $baseURI; } + + /** + * @return int + */ + public function getTimeout() + { + return $this->timeout; + } + + /** + * @param int $timeout + */ + public function setTimeout($timeout) + { + $this->timeout = $timeout; + } } \ No newline at end of file diff --git a/src/Leaseweb/InfluxDB/Database.php b/src/Leaseweb/InfluxDB/Database.php index f62f3bdcc..8a594abd6 100644 --- a/src/Leaseweb/InfluxDB/Database.php +++ b/src/Leaseweb/InfluxDB/Database.php @@ -5,9 +5,9 @@ namespace Leaseweb\InfluxDB; -use GuzzleHttp\Client as httpClient; use Leaseweb\InfluxDB\Database\RetentionPolicy; use Leaseweb\InfluxDB\Query\Builder as QueryBuilder; +use Leaseweb\InfluxDB\Database\Exception as DatabaseException; /** * Class Database @@ -31,22 +31,24 @@ class Database */ protected $client; - /** - * @var httpClient - */ - protected $httpClient; - /** * Construct a database object * * @param string $name * @param Client $client + * + * @throws DatabaseException */ public function __construct($name, Client $client) { $this->client = $client; - $this->httpClient = new Client(array('base_uri' => $this->client->getBaseURI())); + if (!$name) { + throw new DatabaseException('No database name provided'); + } + + $this->name = $name; + } /** @@ -54,24 +56,58 @@ class Database * * @param string $query * @param array $params + * + * @return ResultSet + * + * @throws Exception */ public function query($query, $params = array()) { - $params = array_merge(array('q' => $query, $params)); - - $result = $this->httpClient->get('query', $params); - - die(var_dump($result)); + return $this->client->query($this->name, $query, $params); } /** * Create this database * * @param RetentionPolicy $retentionPolicy + * + * @return ResultSet + * + * @throws DatabaseException + * @throws Exception */ - public function create(RetentionPolicy $retentionPolicy) + public function create(RetentionPolicy $retentionPolicy = null) { - return $this->query(sprintf('CREATE DATABASE %s', $this->name)); + try { + $this->query(sprintf('CREATE DATABASE %s', $this->name)); + + if ($retentionPolicy) { + $this->query($this->getRetentionPolicyQuery('CREATE', $retentionPolicy)); + } + + } catch (\Exception $e) { + throw new DatabaseException( + sprintf('Failed to created database %s, exception: %s', $this->name, $e->getMessage()) + ); + } + } + + /** + * @param RetentionPolicy $retentionPolicy + */ + public function alterRetentionPolicy(RetentionPolicy $retentionPolicy) + { + $this->query($this->getRetentionPolicyQuery('ALTER', $retentionPolicy)); + } + + /** + * @return array + * + * @throws Exception + */ + public function listRetentionPolicies() + { + return $this->query(sprintf('SHOW RETENTION POLICIES %s', $this->name))->getPoints(); } /** @@ -79,7 +115,7 @@ class Database */ public function drop() { - + $this->query(sprintf('DROP DATABASE %s', $this->name)); } /** @@ -92,5 +128,33 @@ class Database return new QueryBuilder($this); } + /** + * @param $method + * @param RetentionPolicy $retentionPolicy + * + * @return string + */ + protected function getRetentionPolicyQuery($method, RetentionPolicy $retentionPolicy) + { + + if (!in_array($method, array('CREATE', 'ALTER'))) { + throw new \InvalidArgumentException(sprintf('%s is not a valid method')); + } + + $query = sprintf( + '%s RETENTION POLICY %s ON %s DURATION %s REPLICATION %s', + $method, + $retentionPolicy->name, + $this->name, + $retentionPolicy->duration, + $retentionPolicy->replication + ); + + if ($retentionPolicy->default) { + $query .= " DEFAULT"; + } + + return $query; + } } \ No newline at end of file diff --git a/src/Leaseweb/InfluxDB/Database/Exception.php b/src/Leaseweb/InfluxDB/Database/Exception.php new file mode 100644 index 000000000..858934f34 --- /dev/null +++ b/src/Leaseweb/InfluxDB/Database/Exception.php @@ -0,0 +1,12 @@ +name = $name; $this->duration = $duration; $this->replication = $replication; - $this->default = $default; + + $this->default = (bool) $default; } } \ No newline at end of file diff --git a/src/Leaseweb/InfluxDB/Query/Builder.php b/src/Leaseweb/InfluxDB/Query/Builder.php index 6117b3d8d..c29863fd6 100644 --- a/src/Leaseweb/InfluxDB/Query/Builder.php +++ b/src/Leaseweb/InfluxDB/Query/Builder.php @@ -6,9 +6,10 @@ namespace Leaseweb\InfluxDB\Query; use Leaseweb\InfluxDB\Database; +use Leaseweb\InfluxDB\ResultSet; /** - * Class QueryBuilder + * Class Builder * * Abstraction class for getting time series out of InfluxDB * @@ -19,7 +20,7 @@ use Leaseweb\InfluxDB\Database; * * $series->select('*')->from('*')->getResult(); * - * @package Leaseweb\InfluxDB + * @package Leaseweb\InfluxDB\Query */ class Builder { @@ -191,9 +192,9 @@ class Builder * * @param bool $raw always return the ResultSeriesObjects, even when using an aggregation function * - * @return array|null + * @return ResultSet */ - public function getResult($raw = false) + public function getResultSet($raw = false) { $query = sprintf("SELECT %s FROM %s", $this->selection, $this->metric); $aggregateKey = null; @@ -217,12 +218,6 @@ class Builder } - $queryResult = $this->db->query($query); - - if ($queryResult && $aggregateKey && !$raw) { - return (float) $queryResult[0]->$aggregateKey; - } - - return $queryResult; + return $this->db->query($query); } } \ No newline at end of file diff --git a/src/Leaseweb/InfluxDB/Query/Exception.php b/src/Leaseweb/InfluxDB/Query/Exception.php new file mode 100644 index 000000000..9c1e5dab9 --- /dev/null +++ b/src/Leaseweb/InfluxDB/Query/Exception.php @@ -0,0 +1,12 @@ + Date: Thu, 18 Jun 2015 16:17:57 +0200 Subject: [PATCH 15/72] Testing database --- src/Leaseweb/InfluxDB/Database.php | 1 + tests/unit/DatabaseTest.php | 42 ++++++++++++++++++++++++++++++ tests/unit/input.example.json | 17 ++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 tests/unit/DatabaseTest.php create mode 100644 tests/unit/input.example.json diff --git a/src/Leaseweb/InfluxDB/Database.php b/src/Leaseweb/InfluxDB/Database.php index 8a594abd6..37ca65cb9 100644 --- a/src/Leaseweb/InfluxDB/Database.php +++ b/src/Leaseweb/InfluxDB/Database.php @@ -110,6 +110,7 @@ class Database return $this->query(sprintf('SHOW RETENTION POLICIES %s', $this->name))->getPoints(); } + /** * Drop this database */ diff --git a/tests/unit/DatabaseTest.php b/tests/unit/DatabaseTest.php new file mode 100644 index 000000000..336ce3a7e --- /dev/null +++ b/tests/unit/DatabaseTest.php @@ -0,0 +1,42 @@ +mockClient = $this->getMockBuilder('\Leaseweb\InfluxDB\Client') + ->disableOriginalConstructor() + ->getMock(); + + $this->mockClient->expects($this->any()) + ->method('getBaseURI') + ->will($this->returnValue($this->equalTo('http://localhost:8086'))); + + $this->db = new Database('influx_test_db', $this->mockClient); + + $this->dataToInsert = file_get_contents(dirname(__FILE__) . '/input.example.json'); + + } + + public function testWrite() + { + $this->assertTrue( + 'mockClient' + ); + } +} \ No newline at end of file diff --git a/tests/unit/input.example.json b/tests/unit/input.example.json new file mode 100644 index 000000000..f47806261 --- /dev/null +++ b/tests/unit/input.example.json @@ -0,0 +1,17 @@ +{ + "database": "mydb", + "retentionPolicy": "mypolicy", + "points": [ + { + "measurement": "cpu_load_short", + "tags": { + "host": "server01", + "region": "us-west" + }, + "time": "2009-11-10T23:00:00Z", + "fields": { + "value": 0.64 + } + } + ] +} \ No newline at end of file From aa25eae8651b9c6975be8620220788e6cfce61e9 Mon Sep 17 00:00:00 2001 From: danibrutal Date: Fri, 19 Jun 2015 09:49:58 +0200 Subject: [PATCH 16/72] Adding Point class to handle Points --- src/Leaseweb/InfluxDB/Database.php | 11 ++++++ src/Leaseweb/InfluxDB/Point.php | 55 ++++++++++++++++++++++++++++++ tests/unit/DatabaseTest.php | 23 +++++++++++-- tests/unit/PointTest.php | 32 +++++++++++++++++ 4 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 src/Leaseweb/InfluxDB/Point.php create mode 100644 tests/unit/PointTest.php diff --git a/src/Leaseweb/InfluxDB/Database.php b/src/Leaseweb/InfluxDB/Database.php index 37ca65cb9..d4de7b973 100644 --- a/src/Leaseweb/InfluxDB/Database.php +++ b/src/Leaseweb/InfluxDB/Database.php @@ -92,6 +92,17 @@ class Database } } + /** + * Writes points into INfluxdb + * @param Point[] $points + */ + public function writePoints(array $points) + { + foreach ($points as $point) { + $point->a(); + } + } + /** * @param RetentionPolicy $retentionPolicy */ diff --git a/src/Leaseweb/InfluxDB/Point.php b/src/Leaseweb/InfluxDB/Point.php new file mode 100644 index 000000000..b324c9a56 --- /dev/null +++ b/src/Leaseweb/InfluxDB/Point.php @@ -0,0 +1,55 @@ +measurement = $measurement; + $this->tags = $tags; + $this->fields = $fields; + $this->timestamp = $timestamp; + } + + /** + * @see: https://influxdb.com/docs/v0.9/concepts/reading_and_writing_data.html + * + * Should return this format + * 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000' + */ + public function __toString() + { + return ""; + /*return sprintf( + '%s,%s %s %s', + $this->measurement, + implode() + );*/ + } + + public function a(){ + + } +} \ No newline at end of file diff --git a/tests/unit/DatabaseTest.php b/tests/unit/DatabaseTest.php index 336ce3a7e..2d357c89e 100644 --- a/tests/unit/DatabaseTest.php +++ b/tests/unit/DatabaseTest.php @@ -5,6 +5,7 @@ namespace Leaseweb\InfluxDB\Test; use Leaseweb\InfluxDB\Client; use Leaseweb\InfluxDB\Database; +use Leaseweb\InfluxDB\Point; class DatabaseTest extends \PHPUnit_Framework_TestCase { @@ -30,13 +31,31 @@ class DatabaseTest extends \PHPUnit_Framework_TestCase $this->db = new Database('influx_test_db', $this->mockClient); $this->dataToInsert = file_get_contents(dirname(__FILE__) . '/input.example.json'); - } + /** + * todo: + */ public function testWrite() { + $point1 = new Point( + 'cpu_load_short', + array('host' =>'server01', 'region'=>'us-west'), + array('value' => 0.64), + 'myTime' + ); + + $point2 = new Point( + 'cpu_load_short', + array('host' =>'server01', 'region'=>'us-west'), + array('value' => 0.84), + 'myTime' + ); + + $this->db->writePoints(array($point1, $point2)); + $this->assertTrue( - 'mockClient' + true ); } } \ No newline at end of file diff --git a/tests/unit/PointTest.php b/tests/unit/PointTest.php new file mode 100644 index 000000000..32916d2a8 --- /dev/null +++ b/tests/unit/PointTest.php @@ -0,0 +1,32 @@ +'server01', 'region'=>'us-west'), + array('value' => 0.64), + 'myTime' + ); + + + $this->assertEquals($expected, (string) $point); + } + +} \ No newline at end of file From d625efdedc9d578a73ce2b1f329d69de1bef70f5 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Fri, 19 Jun 2015 11:23:31 +0200 Subject: [PATCH 17/72] Fixed query builder last method, added median method; fixed adding retention policies --- src/Leaseweb/InfluxDB/Client.php | 62 +++++++++++++++++++------ src/Leaseweb/InfluxDB/Database.php | 7 ++- src/Leaseweb/InfluxDB/Query/Builder.php | 12 +++-- 3 files changed, 61 insertions(+), 20 deletions(-) diff --git a/src/Leaseweb/InfluxDB/Client.php b/src/Leaseweb/InfluxDB/Client.php index 38125bcc2..e3eb5f4c5 100644 --- a/src/Leaseweb/InfluxDB/Client.php +++ b/src/Leaseweb/InfluxDB/Client.php @@ -69,6 +69,11 @@ class Client */ protected $httpClient; + /** + * @var array + */ + protected $options = array(); + /** * @param string $host * @param int $port @@ -87,7 +92,7 @@ class Client $username = '', $password = '', $ssl = false, - $verifySSL = false, + $verifySSL = true, $timeout = 0 // $useUdp = false, // $udpPort = 4444 @@ -103,6 +108,9 @@ class Client if ($ssl) { $this->scheme = 'https'; + $this->options += array( + 'verify' => $verifySSL + ); } // the the base URI @@ -150,9 +158,10 @@ class Client } $params = array_merge(array('q' => $query), $params); + $options = array_merge($this->options, array('query' => $params, 'http_errors' => false)); try { - $response = $this->httpClient->get('query', array('query' => $params, 'http_errors' => false)); + $response = $this->httpClient->get('query', $options); $raw = (string) $response->getBody(); @@ -170,15 +179,24 @@ class Client { $result = $this->query(null, 'SHOW DATABASES')->getPoints(); - $names = array(); - - foreach ($result as $item) { - $names[] = $item['name']; - } - - return $names; + return $this->pointsToArray($result); } + /** + * List all the users + * + * @return array + * @todo implement once issue #3048 is fixed + * + * @throws Exception + */ +// public function listUsers() +// { +// $result = $this->query(null, 'SHOW USERS')->getPoints(); +// +// return $this->pointsToArray($result); +// } + /** * Build the client from a dsn * @@ -186,12 +204,12 @@ class Client * * @param string $dsn * - * @todo finish this functionality + * @todo implement this functionality */ - public static function fromDSN($dsn) - { - $args = array(); - } +// public static function fromDSN($dsn) +// { +// $args = array(); +// } /** * @return mixed @@ -224,4 +242,20 @@ class Client { $this->timeout = $timeout; } + + /** + * @param array $points + * + * @return array + */ + protected function pointsToArray(array $points) + { + $names = array(); + + foreach ($points as $item) { + $names[] = $item['name']; + } + + return $names; + } } \ No newline at end of file diff --git a/src/Leaseweb/InfluxDB/Database.php b/src/Leaseweb/InfluxDB/Database.php index d4de7b973..d18252361 100644 --- a/src/Leaseweb/InfluxDB/Database.php +++ b/src/Leaseweb/InfluxDB/Database.php @@ -82,7 +82,7 @@ class Database $this->query(sprintf('CREATE DATABASE %s', $this->name)); if ($retentionPolicy) { - $this->query($this->getRetentionPolicyQuery('CREATE', $retentionPolicy)); + $this->createRetentionPolicy($retentionPolicy); } } catch (\Exception $e) { @@ -92,6 +92,11 @@ class Database } } + public function createRetentionPolicy(RetentionPolicy $retentionPolicy) + { + $this->query($this->getRetentionPolicyQuery('CREATE', $retentionPolicy)); + } + /** * Writes points into INfluxdb * @param Point[] $points diff --git a/src/Leaseweb/InfluxDB/Query/Builder.php b/src/Leaseweb/InfluxDB/Query/Builder.php index c29863fd6..aa61ce9b9 100644 --- a/src/Leaseweb/InfluxDB/Query/Builder.php +++ b/src/Leaseweb/InfluxDB/Query/Builder.php @@ -88,11 +88,13 @@ class Builder } /** + * @param string $field + * * @return $this */ - public function selectAll() + public function count($field = 'type') { - $this->selection = '*'; + $this->selection = sprintf('count(%s)', $field); return $this; } @@ -102,9 +104,9 @@ class Builder * * @return $this */ - public function count($field = 'type') + public function median($field = 'type') { - $this->selection = sprintf('count(%s)', $field); + $this->selection = sprintf('median(%s)', $field); return $this; } @@ -152,7 +154,7 @@ class Builder */ public function last($field = 'type') { - $this->selection = sprintf('first(%s)', $field); + $this->selection = sprintf('last(%s)', $field); return $this; } From 20e2527a920a4a89195c2008f2f5c70103639765 Mon Sep 17 00:00:00 2001 From: danibrutal Date: Fri, 19 Jun 2015 11:33:44 +0200 Subject: [PATCH 18/72] Changing Client Exception, testing Point --- src/Leaseweb/InfluxDB/Client/Exception.php | 13 +++++++++++++ src/Leaseweb/InfluxDB/Database.php | 2 +- src/Leaseweb/InfluxDB/InfluxDBClientError.php | 12 ------------ src/Leaseweb/InfluxDB/Point.php | 19 ++++++++++++++----- src/Leaseweb/InfluxDB/ResultSet.php | 12 +++++++----- tests/unit/PointTest.php | 5 +---- tests/unit/ResultSetTest.php | 4 ++-- 7 files changed, 38 insertions(+), 29 deletions(-) create mode 100644 src/Leaseweb/InfluxDB/Client/Exception.php delete mode 100644 src/Leaseweb/InfluxDB/InfluxDBClientError.php diff --git a/src/Leaseweb/InfluxDB/Client/Exception.php b/src/Leaseweb/InfluxDB/Client/Exception.php new file mode 100644 index 000000000..8d4c258d0 --- /dev/null +++ b/src/Leaseweb/InfluxDB/Client/Exception.php @@ -0,0 +1,13 @@ +a(); + //$point->a(); } } diff --git a/src/Leaseweb/InfluxDB/InfluxDBClientError.php b/src/Leaseweb/InfluxDB/InfluxDBClientError.php deleted file mode 100644 index 75b8dbc22..000000000 --- a/src/Leaseweb/InfluxDB/InfluxDBClientError.php +++ /dev/null @@ -1,12 +0,0 @@ -measurement, - implode() - );*/ + $this->arrayToString($this->tags), + $this->arrayToString($this->fields), + $this->timestamp + ); } - public function a(){ + private function arrayToString(array $arr) + { + $strParts = array(); + foreach ($arr as $key=> $value) { + $strParts[]="{$key}={$value}"; + } + + return implode(",", $strParts); } + } \ No newline at end of file diff --git a/src/Leaseweb/InfluxDB/ResultSet.php b/src/Leaseweb/InfluxDB/ResultSet.php index f9c932b91..4380c33f9 100644 --- a/src/Leaseweb/InfluxDB/ResultSet.php +++ b/src/Leaseweb/InfluxDB/ResultSet.php @@ -5,6 +5,8 @@ namespace Leaseweb\InfluxDB; +use Leaseweb\InfluxDB\Client\Exception as ClientException; + /** * Class ResultSet * @@ -26,7 +28,7 @@ class ResultSet * @param $raw * * @throws \InvalidArgumentException - * @throws InfluxDBClientError + * @throws Exception */ public function __construct($raw) { @@ -40,11 +42,11 @@ class ResultSet // There was an error in the query thrown by influxdb if (isset($this->parsedResults['error'])) { - throw new InfluxDBClientError($this->parsedResults['error']); + throw new ClientException($this->parsedResults['error']); // Check if there are errors in the first serie } elseif (isset($this->parsedResults['results'][0]['error'])) { - throw new InfluxDBClientError($this->parsedResults['results'][0]['error']); + throw new ClientException($this->parsedResults['results'][0]['error']); } } @@ -77,7 +79,7 @@ class ResultSet * results is an array of objects, one for each query, * each containing the keys for a series * - * @throws InfluxDBClientError + * @throws Exception * * @return array $series */ @@ -86,7 +88,7 @@ class ResultSet $pickSeries = function ($object) { if (isset($object['error'])) { - throw new InfluxDBClientError($object['error']); + throw new ClientException($object['error']); } return $object['series']; diff --git a/tests/unit/PointTest.php b/tests/unit/PointTest.php index 32916d2a8..ea693cf76 100644 --- a/tests/unit/PointTest.php +++ b/tests/unit/PointTest.php @@ -13,10 +13,9 @@ use Leaseweb\InfluxDB\Point; class PointTest extends \PHPUnit_Framework_TestCase { - public function testPointStringRepresentation() { - $expected = 'cpu_load_short,host=server01,region=us-west value=0.64 mytime'; + $expected = 'cpu_load_short,host=server01,region=us-west value=0.64 myTime'; $point = new Point( 'cpu_load_short', @@ -25,8 +24,6 @@ class PointTest extends \PHPUnit_Framework_TestCase 'myTime' ); - $this->assertEquals($expected, (string) $point); } - } \ No newline at end of file diff --git a/tests/unit/ResultSetTest.php b/tests/unit/ResultSetTest.php index 024da364f..d68da1cd8 100644 --- a/tests/unit/ResultSetTest.php +++ b/tests/unit/ResultSetTest.php @@ -26,7 +26,7 @@ class ResultSetTest extends \PHPUnit_Framework_TestCase /** * Throws Exception if something went wrong with influxDB - * @expectedException \Leaseweb\InfluxDB\InfluxDBClientError + * @expectedException \Leaseweb\InfluxDB\Exception */ public function testThrowsInfluxDBException() { @@ -42,7 +42,7 @@ EOD; /** * Throws Exception if something went wrong with influxDB after processing the query - * @expectedException \Leaseweb\InfluxDB\InfluxDBClientError + * @expectedException \Leaseweb\InfluxDB\Exception */ public function testThrowsInfluxDBExceptionIfAnyErrorInSeries() { From e4f5bb94d6a71e8c4548447cf3970b9f653d9664 Mon Sep 17 00:00:00 2001 From: danibrutal Date: Fri, 19 Jun 2015 11:47:27 +0200 Subject: [PATCH 19/72] ResultSet bugfix if tags key is missing in the result --- src/Leaseweb/InfluxDB/Database.php | 15 ++++++-- src/Leaseweb/InfluxDB/ResultSet.php | 2 +- tests/unit/DatabaseTest.php | 2 +- tests/unit/ResultSetTest.php | 18 ++++++++++ tests/unit/result-no-tags.example.json | 47 ++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 tests/unit/result-no-tags.example.json diff --git a/src/Leaseweb/InfluxDB/Database.php b/src/Leaseweb/InfluxDB/Database.php index 0dedc4e58..4f92ba3f3 100644 --- a/src/Leaseweb/InfluxDB/Database.php +++ b/src/Leaseweb/InfluxDB/Database.php @@ -99,13 +99,24 @@ class Database /** * Writes points into INfluxdb - * @param Point[] $points + * + * @param array $points + * @return ResultSet */ public function writePoints(array $points) { + $payload = array(); + foreach ($points as $point) { - //$point->a(); + + if (! $point instanceof Point) { + throw new \InvalidArgumentException('Array of Point should be passed'); + } + + $payload[] = (string) $point; } + + return $this->query(implode("\n", $payload)); } /** diff --git a/src/Leaseweb/InfluxDB/ResultSet.php b/src/Leaseweb/InfluxDB/ResultSet.php index 4380c33f9..64f8cff90 100644 --- a/src/Leaseweb/InfluxDB/ResultSet.php +++ b/src/Leaseweb/InfluxDB/ResultSet.php @@ -64,7 +64,7 @@ class ResultSet if ((empty($metricName) && empty($tags)) || $serie['name'] == $metricName - || array_intersect($tags, $serie['tags']) + || (isset($serie['tags']) && array_intersect($tags, $serie['tags'])) ) { $points = array_merge($points, $this->getPointsFromSerie($serie)); } diff --git a/tests/unit/DatabaseTest.php b/tests/unit/DatabaseTest.php index 2d357c89e..cbb255b85 100644 --- a/tests/unit/DatabaseTest.php +++ b/tests/unit/DatabaseTest.php @@ -52,7 +52,7 @@ class DatabaseTest extends \PHPUnit_Framework_TestCase 'myTime' ); - $this->db->writePoints(array($point1, $point2)); + //$this->db->writePoints(array($point1, $point2)); $this->assertTrue( true diff --git a/tests/unit/ResultSetTest.php b/tests/unit/ResultSetTest.php index d68da1cd8..a85c74f9d 100644 --- a/tests/unit/ResultSetTest.php +++ b/tests/unit/ResultSetTest.php @@ -60,6 +60,24 @@ EOD; new ResultSet($errorResult); } + /** + * We can get points from measurement + */ + public function testGetPointsFromNameWithoudTags() + { + $resultJsonExample = file_get_contents(dirname(__FILE__) . '/result-no-tags.example.json'); + $this->resultSet = new ResultSet($resultJsonExample); + + $measurementName = 'cpu_load_short'; + $expectedNumberOfPoints = 2; + + $points = $this->resultSet->getPoints($measurementName); + + $this->assertTrue(is_array($points)); + + $this->assertCount($expectedNumberOfPoints, $points); + } + /** * We can get points from measurement */ diff --git a/tests/unit/result-no-tags.example.json b/tests/unit/result-no-tags.example.json new file mode 100644 index 000000000..feba13f25 --- /dev/null +++ b/tests/unit/result-no-tags.example.json @@ -0,0 +1,47 @@ +{ + "results": [ + { + "series": [ + { + "name": "cpu_load_short", + "columns": [ + "time", + "value" + ], + "values": [ + [ + "2015-01-29T21:51:28.968422294Z", + 0.64 + ] + ] + }, + { + "name": "cpu_load_short", + "columns": [ + "time", + "value" + ], + "values": [ + [ + "2015-01-29T21:51:28.968422294Z", + 0.65 + ] + ] + }, + { + "name": "other_serie", + "columns": [ + "time", + "value" + ], + "values": [ + [ + "2015-01-29T21:51:28.968422294Z", + 0.66 + ] + ] + } + ] + } + ] +} \ No newline at end of file From 90277f14a8abf3fabd3f511ae6d9143d12bf30dd Mon Sep 17 00:00:00 2001 From: danibrutal Date: Fri, 19 Jun 2015 12:04:25 +0200 Subject: [PATCH 20/72] Writing Points tests --- src/Leaseweb/InfluxDB/Database.php | 8 ++++++++ src/Leaseweb/InfluxDB/Point.php | 2 ++ tests/unit/DatabaseTest.php | 18 +++++++++--------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Leaseweb/InfluxDB/Database.php b/src/Leaseweb/InfluxDB/Database.php index 4f92ba3f3..b757e602a 100644 --- a/src/Leaseweb/InfluxDB/Database.php +++ b/src/Leaseweb/InfluxDB/Database.php @@ -51,6 +51,14 @@ class Database } + /** + * @return string db name + */ + public function getName() + { + return $this->name; + } + /** * Query influxDB * diff --git a/src/Leaseweb/InfluxDB/Point.php b/src/Leaseweb/InfluxDB/Point.php index debc659c3..2df53855e 100644 --- a/src/Leaseweb/InfluxDB/Point.php +++ b/src/Leaseweb/InfluxDB/Point.php @@ -20,6 +20,8 @@ class Point private $timestamp; /** + * todo: Handle optional timestamp + * * @param $measurement * @param array $tags * @param array $fields diff --git a/tests/unit/DatabaseTest.php b/tests/unit/DatabaseTest.php index cbb255b85..e4dddc3e1 100644 --- a/tests/unit/DatabaseTest.php +++ b/tests/unit/DatabaseTest.php @@ -33,10 +33,8 @@ class DatabaseTest extends \PHPUnit_Framework_TestCase $this->dataToInsert = file_get_contents(dirname(__FILE__) . '/input.example.json'); } - /** - * todo: - */ - public function testWrite() + + public function testWritePointsInASingleCall() { $point1 = new Point( 'cpu_load_short', @@ -44,7 +42,6 @@ class DatabaseTest extends \PHPUnit_Framework_TestCase array('value' => 0.64), 'myTime' ); - $point2 = new Point( 'cpu_load_short', array('host' =>'server01', 'region'=>'us-west'), @@ -52,10 +49,13 @@ class DatabaseTest extends \PHPUnit_Framework_TestCase 'myTime' ); - //$this->db->writePoints(array($point1, $point2)); + $payloadExpected ="$point1\n$point2"; - $this->assertTrue( - true - ); + $this->mockClient->expects($this->once()) + ->method('query') + ->with($this->equalTo($this->db->getName()), $this->equalTo($payloadExpected)) + ->will($this->returnValue($this->equalTo('http://localhost:8086'))); + + $this->db->writePoints(array($point1, $point2)); } } \ No newline at end of file From 6b8d03704e38a52018b8c885de04583437710eb1 Mon Sep 17 00:00:00 2001 From: danibrutal Date: Fri, 19 Jun 2015 15:46:02 +0200 Subject: [PATCH 21/72] Client - write method --- src/Leaseweb/InfluxDB/Client.php | 20 ++++++++++++++++++++ src/Leaseweb/InfluxDB/Database.php | 10 +++++----- src/Leaseweb/InfluxDB/Point.php | 13 +++++++++---- tests/unit/DatabaseTest.php | 3 +-- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/Leaseweb/InfluxDB/Client.php b/src/Leaseweb/InfluxDB/Client.php index e3eb5f4c5..22a52d672 100644 --- a/src/Leaseweb/InfluxDB/Client.php +++ b/src/Leaseweb/InfluxDB/Client.php @@ -172,6 +172,26 @@ class Client } } + /** + * @param $database + * @param $data + * @return bool + * @throws Exception + */ + public function write($database, $data) + { + try { + $this->httpClient->post( + $this->getBaseURI() . '/write?db=' . $database, + array('body' => $data) + ); + } catch (\Exception $e) { + throw new Exception(sprintf('Writing has failed, exception: %s', $e->getMessage())); + } + + return true; + } + /** * List all the databases */ diff --git a/src/Leaseweb/InfluxDB/Database.php b/src/Leaseweb/InfluxDB/Database.php index b757e602a..5946b9664 100644 --- a/src/Leaseweb/InfluxDB/Database.php +++ b/src/Leaseweb/InfluxDB/Database.php @@ -63,7 +63,7 @@ class Database * Query influxDB * * @param string $query - * @param array $params + * @param array $params * * @return ResultSet * @@ -71,7 +71,7 @@ class Database */ public function query($query, $params = array()) { - return $this->client->query($this->name, $query, $params); + return $this->client->query($this->name, $query, $params); } /** @@ -108,7 +108,7 @@ class Database /** * Writes points into INfluxdb * - * @param array $points + * @param Point [] * @return ResultSet */ public function writePoints(array $points) @@ -117,14 +117,14 @@ class Database foreach ($points as $point) { - if (! $point instanceof Point) { + if (!$point instanceof Point) { throw new \InvalidArgumentException('Array of Point should be passed'); } $payload[] = (string) $point; } - return $this->query(implode("\n", $payload)); + return $this->client->write($this->name, implode(PHP_EOL, $payload)); } /** diff --git a/src/Leaseweb/InfluxDB/Point.php b/src/Leaseweb/InfluxDB/Point.php index 2df53855e..8ac6705c7 100644 --- a/src/Leaseweb/InfluxDB/Point.php +++ b/src/Leaseweb/InfluxDB/Point.php @@ -2,7 +2,11 @@ namespace Leaseweb\InfluxDB; - +/** + * Class Point + * + * @package Leaseweb\InfluxDB + */ class Point { private $measurement; @@ -20,7 +24,8 @@ class Point private $timestamp; /** - * todo: Handle optional timestamp + * The timestamp is optional. + * If you do not specify a timestamp the server’s local timestamp will be used * * @param $measurement * @param array $tags @@ -56,8 +61,8 @@ class Point { $strParts = array(); - foreach ($arr as $key=> $value) { - $strParts[]="{$key}={$value}"; + foreach ($arr as $key => $value) { + $strParts[] = "{$key}={$value}"; } return implode(",", $strParts); diff --git a/tests/unit/DatabaseTest.php b/tests/unit/DatabaseTest.php index e4dddc3e1..e1697b799 100644 --- a/tests/unit/DatabaseTest.php +++ b/tests/unit/DatabaseTest.php @@ -53,8 +53,7 @@ class DatabaseTest extends \PHPUnit_Framework_TestCase $this->mockClient->expects($this->once()) ->method('query') - ->with($this->equalTo($this->db->getName()), $this->equalTo($payloadExpected)) - ->will($this->returnValue($this->equalTo('http://localhost:8086'))); + ->with($this->equalTo($this->db->getName()), $this->equalTo($payloadExpected)); $this->db->writePoints(array($point1, $point2)); } From 7291a056edefcf05fd3a1589b0bc1524cabd4f9d Mon Sep 17 00:00:00 2001 From: danibrutal Date: Mon, 22 Jun 2015 09:44:26 +0200 Subject: [PATCH 22/72] Bugfix write method tests --- tests/unit/DatabaseTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/DatabaseTest.php b/tests/unit/DatabaseTest.php index e1697b799..2689fa83d 100644 --- a/tests/unit/DatabaseTest.php +++ b/tests/unit/DatabaseTest.php @@ -52,7 +52,7 @@ class DatabaseTest extends \PHPUnit_Framework_TestCase $payloadExpected ="$point1\n$point2"; $this->mockClient->expects($this->once()) - ->method('query') + ->method('write') ->with($this->equalTo($this->db->getName()), $this->equalTo($payloadExpected)); $this->db->writePoints(array($point1, $point2)); From 0091131d6b53dd43f4fdea1b9eca03526ed15163 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Mon, 22 Jun 2015 14:51:48 +0200 Subject: [PATCH 23/72] Added from dsn method --- src/Leaseweb/InfluxDB/Client.php | 71 ++++++++++++++++++++++------- src/Leaseweb/InfluxDB/Database.php | 8 ++++ src/Leaseweb/InfluxDB/ResultSet.php | 5 +- 3 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/Leaseweb/InfluxDB/Client.php b/src/Leaseweb/InfluxDB/Client.php index 22a52d672..49d0df05f 100644 --- a/src/Leaseweb/InfluxDB/Client.php +++ b/src/Leaseweb/InfluxDB/Client.php @@ -7,6 +7,8 @@ namespace Leaseweb\InfluxDB; use GuzzleHttp\Client as httpClient; +use Leaseweb\InfluxDB\Client\Exception as ClientException; + /** * Class Client * @@ -84,7 +86,6 @@ class Client * @param int $timeout * * @todo add UDP support - * @todo add SSL support */ public function __construct( $host, @@ -94,8 +95,6 @@ class Client $ssl = false, $verifySSL = true, $timeout = 0 -// $useUdp = false, -// $udpPort = 4444 ) { @@ -206,31 +205,71 @@ class Client * List all the users * * @return array - * @todo implement once issue #3048 is fixed * * @throws Exception */ -// public function listUsers() -// { -// $result = $this->query(null, 'SHOW USERS')->getPoints(); -// -// return $this->pointsToArray($result); -// } + public function listUsers() + { + $result = $this->query(null, 'SHOW USERS')->getPoints(); + + return $this->pointsToArray($result); + } /** * Build the client from a dsn * - * Example: tcp+influxdb://username:pass@localhost:8086/databasename', timeout=5 + * Example: https+influxdb://username:pass@localhost:8086/databasename', timeout=5 * * @param string $dsn * - * @todo implement this functionality + * @param int $timeout + * @param bool $verifySSL + * + * @return Client|Database + * + * @throws ClientException */ -// public static function fromDSN($dsn) -// { -// $args = array(); -// } + public static function fromDSN($dsn, $timeout = 0, $verifySSL = false) + { + $connParams = parse_url($dsn); + $schemeInfo = explode('+', $connParams['scheme']); + $dbName = null; + if (count($schemeInfo) == 1) { + $modifier = null; + $scheme = $schemeInfo[0]; + } else { + $modifier = $schemeInfo[0]; + $scheme = $schemeInfo[1]; + } + + if ($scheme != 'influxdb') { + throw new ClientException(sprintf('%s is not a valid scheme', $scheme)); + } + + $ssl = ($modifier && $modifier == 'https' ? true : false); + + if ($connParams['path']) { + $dbName = substr($connParams['path'], 1); + } + + $client = new self( + $connParams['host'], + $connParams['port'], + $connParams['user'], + $connParams['pass'], + $ssl, + $verifySSL, + $timeout + ); + + $return = $client; + if ($dbName) { + $return = $client->db($dbName); + } + + return $return; + } /** * @return mixed */ diff --git a/src/Leaseweb/InfluxDB/Database.php b/src/Leaseweb/InfluxDB/Database.php index 5946b9664..40cd5b45c 100644 --- a/src/Leaseweb/InfluxDB/Database.php +++ b/src/Leaseweb/InfluxDB/Database.php @@ -164,6 +164,14 @@ class Database return new QueryBuilder($this); } + /** + * @return Client + */ + public function getClient() + { + return $this->client; + } + /** * @param $method * @param RetentionPolicy $retentionPolicy diff --git a/src/Leaseweb/InfluxDB/ResultSet.php b/src/Leaseweb/InfluxDB/ResultSet.php index 64f8cff90..a56b3fc1e 100644 --- a/src/Leaseweb/InfluxDB/ResultSet.php +++ b/src/Leaseweb/InfluxDB/ResultSet.php @@ -62,9 +62,10 @@ class ResultSet foreach ($this->getSeries() as $serie) { - if ((empty($metricName) && empty($tags)) + if ((empty($metricName) && empty($tags) || $serie['name'] == $metricName - || (isset($serie['tags']) && array_intersect($tags, $serie['tags'])) + || (isset($serie['tags']) && array_intersect($tags, $serie['tags']))) + && isset($serie['values']) ) { $points = array_merge($points, $this->getPointsFromSerie($serie)); } From 54fbd31ce220c5803f87d1370d8cd118765e4b66 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Tue, 23 Jun 2015 09:19:24 +0200 Subject: [PATCH 24/72] Changed namespace to \\InfluxDB --- README.md | 2 +- composer.json | 4 ++-- composer.lock | 2 +- src/{Leaseweb => }/InfluxDB/Client.php | 6 +++--- src/InfluxDB/Client/Exception.php | 13 +++++++++++++ src/{Leaseweb => }/InfluxDB/Database.php | 10 +++++----- src/InfluxDB/Database/Exception.php | 12 ++++++++++++ .../InfluxDB/Database/RetentionPolicy.php | 4 ++-- src/{Leaseweb => }/InfluxDB/Exception.php | 2 +- src/{Leaseweb => }/InfluxDB/Point.php | 4 ++-- src/{Leaseweb => }/InfluxDB/Query/Builder.php | 8 ++++---- src/InfluxDB/Query/Exception.php | 12 ++++++++++++ src/{Leaseweb => }/InfluxDB/ResultSet.php | 6 +++--- src/Leaseweb/InfluxDB/Client/Exception.php | 13 ------------- src/Leaseweb/InfluxDB/Database/Exception.php | 12 ------------ src/Leaseweb/InfluxDB/Query/Exception.php | 12 ------------ tests/unit/ClientTest.php | 4 ++-- tests/unit/DatabaseTest.php | 10 +++++----- tests/unit/PointTest.php | 4 ++-- tests/unit/ResultSetTest.php | 8 ++++---- 20 files changed, 74 insertions(+), 74 deletions(-) rename src/{Leaseweb => }/InfluxDB/Client.php (98%) create mode 100644 src/InfluxDB/Client/Exception.php rename src/{Leaseweb => }/InfluxDB/Database.php (94%) create mode 100644 src/InfluxDB/Database/Exception.php rename src/{Leaseweb => }/InfluxDB/Database/RetentionPolicy.php (91%) rename src/{Leaseweb => }/InfluxDB/Exception.php (78%) rename src/{Leaseweb => }/InfluxDB/Point.php (96%) rename src/{Leaseweb => }/InfluxDB/Query/Builder.php (97%) create mode 100644 src/InfluxDB/Query/Exception.php rename src/{Leaseweb => }/InfluxDB/ResultSet.php (95%) delete mode 100644 src/Leaseweb/InfluxDB/Client/Exception.php delete mode 100644 src/Leaseweb/InfluxDB/Database/Exception.php delete mode 100644 src/Leaseweb/InfluxDB/Query/Exception.php diff --git a/README.md b/README.md index 600553ba6..9cea2d410 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Initialize a new client object: ```php -$client = new Leaseweb\InfluxDB\Client($host, $port); +$client = new InfluxDB\Client($host, $port); ``` diff --git a/composer.json b/composer.json index 5308120ac..b969c7b3d 100644 --- a/composer.json +++ b/composer.json @@ -22,12 +22,12 @@ }, "autoload": { "psr-4" : { - "Leaseweb\\InfluxDB\\": "src/Leaseweb/InfluxDB" + "InfluxDB\\": "src/InfluxDB" } }, "autoload-dev": { "psr-4": { - "Leaseweb\\InfluxDB\\Test\\": "tests" + "InfluxDB\\Test\\": "tests" } } } diff --git a/composer.lock b/composer.lock index 0613c1ffe..3040b508d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "d4cd96b7a6d552bb16ed5847dd32d4e3", + "hash": "ef84333e4b0fdb96255d8f56a4d42e3b", "packages": [ { "name": "guzzlehttp/guzzle", diff --git a/src/Leaseweb/InfluxDB/Client.php b/src/InfluxDB/Client.php similarity index 98% rename from src/Leaseweb/InfluxDB/Client.php rename to src/InfluxDB/Client.php index 49d0df05f..9540a2a84 100644 --- a/src/Leaseweb/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -3,16 +3,16 @@ * @author Stephen "TheCodeAssassin" Hoogendijk */ -namespace Leaseweb\InfluxDB; +namespace InfluxDB; use GuzzleHttp\Client as httpClient; -use Leaseweb\InfluxDB\Client\Exception as ClientException; +use InfluxDB\Client\Exception as ClientException; /** * Class Client * - * @package Leaseweb\InfluxDB + * @package InfluxDB */ class Client { diff --git a/src/InfluxDB/Client/Exception.php b/src/InfluxDB/Client/Exception.php new file mode 100644 index 000000000..1b446a2ac --- /dev/null +++ b/src/InfluxDB/Client/Exception.php @@ -0,0 +1,13 @@ + */ -namespace Leaseweb\InfluxDB\Query; +namespace InfluxDB\Query; -use Leaseweb\InfluxDB\Database; -use Leaseweb\InfluxDB\ResultSet; +use InfluxDB\Database; +use InfluxDB\ResultSet; /** * Class Builder @@ -20,7 +20,7 @@ use Leaseweb\InfluxDB\ResultSet; * * $series->select('*')->from('*')->getResult(); * - * @package Leaseweb\InfluxDB\Query + * @package InfluxDB\Query */ class Builder { diff --git a/src/InfluxDB/Query/Exception.php b/src/InfluxDB/Query/Exception.php new file mode 100644 index 000000000..4571efb74 --- /dev/null +++ b/src/InfluxDB/Query/Exception.php @@ -0,0 +1,12 @@ +mockClient = $this->getMockBuilder('\Leaseweb\InfluxDB\Client') + $this->mockClient = $this->getMockBuilder('\InfluxDB\Client') ->disableOriginalConstructor() ->getMock(); diff --git a/tests/unit/PointTest.php b/tests/unit/PointTest.php index ea693cf76..d57713b37 100644 --- a/tests/unit/PointTest.php +++ b/tests/unit/PointTest.php @@ -6,10 +6,10 @@ * Time: 17:39 */ -namespace Leaseweb\InfluxDB\Test; +namespace InfluxDB\Test; -use Leaseweb\InfluxDB\Point; +use InfluxDB\Point; class PointTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/unit/ResultSetTest.php b/tests/unit/ResultSetTest.php index a85c74f9d..4c04bf1e9 100644 --- a/tests/unit/ResultSetTest.php +++ b/tests/unit/ResultSetTest.php @@ -1,7 +1,7 @@ Date: Tue, 23 Jun 2015 09:58:32 +0200 Subject: [PATCH 25/72] Fixed automated testing --- phpunit.xml | 2 +- tests/bootstrap.php | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 tests/bootstrap.php diff --git a/phpunit.xml b/phpunit.xml index 102011e1c..9913a0eda 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,5 +1,5 @@ - Date: Wed, 24 Jun 2015 09:26:45 +0200 Subject: [PATCH 26/72] Added travis.yml file --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..8e1ab4ce0 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: php +php: + - 5.3 + - 5.4 + - 5.5 + - 5.6 + +install: + - composer install \ No newline at end of file From a3405a7c15f77d2dbff266cebe7abf5ca5bf7bc4 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 25 Jun 2015 11:48:30 +0200 Subject: [PATCH 27/72] Reverted guzzle to v.5 to support php 5.4, increased verbosity and improved internal api; improved readme --- README.md | 119 ++++++++++++++++++- composer.json | 2 +- composer.lock | 201 +++++++++++++++------------------ src/InfluxDB/Client.php | 11 +- src/InfluxDB/Database.php | 13 ++- src/InfluxDB/Point.php | 69 ++++++++--- src/InfluxDB/Query/Builder.php | 33 ++++-- src/InfluxDB/ResultSet.php | 2 +- tests/unit/DatabaseTest.php | 12 +- tests/unit/PointTest.php | 11 +- 10 files changed, 313 insertions(+), 160 deletions(-) diff --git a/README.md b/README.md index 9cea2d410..2ab4bfc51 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # influxdb-php ## InfluxDB client library for PHP -###Overview +### Overview This library was created to have php port of the python influxdb client. This way there will be a common abstraction library between different programming languages. -###Usage +### Getting started Initialize a new client object: @@ -18,3 +18,118 @@ $client = new InfluxDB\Client($host, $port); ``` This will create a new client object which you can use to read and write points to InfluxDB. + +It's also possible to create a client from a DSN: + +```php + + // directly get the database object + $database = InfluxDB\Client::fromDSN(sprintf('influxdb://user:pass@%s:%s/%s', $host, $port, $dbname)); + + // get the client to retrieve other databases + $client = $database->getClient(); +```php + +### Reading + +To fetch records from InfluxDB you can do a query directly on a database: + +```php + + + // executing a query will yield a resultset object + $result = $database->query('select * from test_metric LIMIT 5'); + + // get the points from the resultset yields an array + $points = $result->getPoints(); + +``` + +It's also possible to use the QueryBuilder object. This is a class that simplifies the process of building queries. + +```php + $result = $database->getQueryBuilder() + ->select('cpucount') + ->from('test_metric') + ->limit(2) + ->getResultSet()->getPoints(); +``` + +### Writing data + +Writing data is done by providing an array of points to the writePoints method on a database: + +```php + + $newPoints = $database->writePoints( + array( + new Point( + 'test_metric', + 0.64, + array('host' => 'server01', 'region' => 'us-west'), + array('cpucount' => 10) + ), + new Point( + 'test_metric', + 0.84, + array('host' => 'server01', 'region' => 'us-west'), + array('cpucount' => 10) + ) + ) + ); + +``` + +The name of a measurement and the value are mandatory. Additional fields, tags and a timestamp are optional. +InfluxDB takes the current time as the default timestamp. + +It's possible to add multiple [fields](https://influxdb.com/docs/v0.9/concepts/key_concepts.html) when writing +measurements to InfluxDB. The point class allows one to easily write data in batches to influxDB. + +### Creating databases + +When creating a database a default retention policy is added. This retention policy does not have a duration +so the data will be flushed with the memory. + +This library makes it easy to provide a retention policy when creating a database: + +```php + + // create the client + $client = new \InfluxDB\Client($host, $port, '', ''); + + // create the database with a retention policy + $result = $database->create(new RetentionPolicy('test', '5d', 1, true)); + +``` + +You can also alter retention policies: + +```php + $database->alterRetentionPolicy(new RetentionPolicy('test', '2d', 5, true)); +``` + +and list them: + +```php + $result = $database->listRetentionPolicies(); +``` + +### Client functions + +Some functions are too general for a database. So these are available in the client: + +```php + + // list users + $result = $client->listUsers(); + + // list databases + $result = $client->listDatabases(); +``` + +## Changelog + +0.1 +------ +Initial release \ No newline at end of file diff --git a/composer.json b/composer.json index b969c7b3d..73f3b4f75 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ ], "require": { "php": ">=5.3", - "guzzlehttp/guzzle": "~6.0" + "guzzlehttp/guzzle": "~5.0" }, "scripts": { "post-install-cmd": [ diff --git a/composer.lock b/composer.lock index 3040b508d..0a9d8afcd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,42 +4,32 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "ef84333e4b0fdb96255d8f56a4d42e3b", + "hash": "10abd66a90e1473453cbda87799ed079", "packages": [ { "name": "guzzlehttp/guzzle", - "version": "dev-master", + "version": "5.3.x-dev", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "0da18ca6654b98a1d57cc9278331a7f7491d0d04" + "reference": "fd861570a9c3c28d98f418feea1f43f6268bdfa0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/0da18ca6654b98a1d57cc9278331a7f7491d0d04", - "reference": "0da18ca6654b98a1d57cc9278331a7f7491d0d04", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/fd861570a9c3c28d98f418feea1f43f6268bdfa0", + "reference": "fd861570a9c3c28d98f418feea1f43f6268bdfa0", "shasum": "" }, "require": { - "guzzlehttp/promises": "~1.0", - "guzzlehttp/psr7": "~1.0", - "php": ">=5.5.0" + "guzzlehttp/ringphp": "^1.1", + "php": ">=5.4.0" }, "require-dev": { "ext-curl": "*", - "phpunit/phpunit": "~4.0", - "psr/log": "~1.0" + "phpunit/phpunit": "^4.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.0-dev" - } - }, "autoload": { - "files": [ - "src/functions.php" - ], "psr-4": { "GuzzleHttp\\": "src/" } @@ -55,7 +45,7 @@ "homepage": "https://github.com/mtdowling" } ], - "description": "Guzzle is a PHP HTTP client library", + "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", "homepage": "http://guzzlephp.org/", "keywords": [ "client", @@ -66,96 +56,44 @@ "rest", "web service" ], - "time": "2015-06-14 02:43:56" + "time": "2015-06-03 05:11:42" }, { - "name": "guzzlehttp/promises", + "name": "guzzlehttp/ringphp", "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "156f6915a89ca2cc9a3b36abef65f336ce68c754" + "url": "https://github.com/guzzle/RingPHP.git", + "reference": "9465032ac5d6beaa55f10923403e6e1c36018d9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/156f6915a89ca2cc9a3b36abef65f336ce68c754", - "reference": "156f6915a89ca2cc9a3b36abef65f336ce68c754", - "shasum": "" - }, - "require": { - "php": ">=5.5.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, - "files": [ - "src/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle promises library", - "keywords": [ - "promise" - ], - "time": "2015-06-16 01:16:05" - }, - { - "name": "guzzlehttp/psr7", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "644db73bfa1571af785172887836d6ec01d787ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/644db73bfa1571af785172887836d6ec01d787ed", - "reference": "644db73bfa1571af785172887836d6ec01d787ed", + "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/9465032ac5d6beaa55f10923403e6e1c36018d9c", + "reference": "9465032ac5d6beaa55f10923403e6e1c36018d9c", "shasum": "" }, "require": { + "guzzlehttp/streams": "~3.0", "php": ">=5.4.0", - "psr/http-message": "~1.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" + "react/promise": "~2.0" }, "require-dev": { + "ext-curl": "*", "phpunit/phpunit": "~4.0" }, + "suggest": { + "ext-curl": "Guzzle will use specific adapters if cURL is present" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" } }, "autoload": { "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - }, - "files": [ - "src/functions.php" - ] + "GuzzleHttp\\Ring\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -168,41 +106,38 @@ "homepage": "https://github.com/mtdowling" } ], - "description": "PSR-7 message implementation", - "keywords": [ - "http", - "message", - "stream", - "uri" - ], - "time": "2015-06-16 01:05:58" + "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.", + "time": "2015-05-21 17:23:02" }, { - "name": "psr/http-message", + "name": "guzzlehttp/streams", "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298" + "url": "https://github.com/guzzle/streams.git", + "reference": "d1f8a6c55f0f753cfd6f6755856473eb02cedb19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", - "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "url": "https://api.github.com/repos/guzzle/streams/zipball/d1f8a6c55f0f753cfd6f6755856473eb02cedb19", + "reference": "d1f8a6c55f0f753cfd6f6755856473eb02cedb19", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { "psr-4": { - "Psr\\Http\\Message\\": "src/" + "GuzzleHttp\\Stream\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -211,20 +146,62 @@ ], "authors": [ { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" } ], - "description": "Common interface for HTTP messages", + "description": "Provides a simple abstraction over streams of data", + "homepage": "http://guzzlephp.org/", "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" + "Guzzle", + "stream" ], - "time": "2015-05-04 20:22:00" + "time": "2015-01-22 00:01:34" + }, + { + "name": "react/promise", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/365fcee430dfa4ace1fbc75737ca60ceea7eeeef", + "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "React\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@googlemail.com" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "time": "2014-12-30 13:32:42" } ], "packages-dev": [], diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index 9540a2a84..4306ffe7e 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -116,10 +116,11 @@ class Client $this->setBaseURI(sprintf('%s://%s:%d', $this->scheme, $this->host, $this->port)); $this->httpClient = new httpClient(array( - 'base_uri' => $this->getBaseURI(), + 'base_url' => $this->getBaseURI(), 'timeout' => $this->getTimeout() ) ); + } /** @@ -156,11 +157,12 @@ class Client $params += array('db' => $database); } - $params = array_merge(array('q' => $query), $params); - $options = array_merge($this->options, array('query' => $params, 'http_errors' => false)); + $params = '?'.http_build_query(array_merge(array('q' => $query), $params)); + + $options = array_merge($this->options, array('exceptions' => false)); try { - $response = $this->httpClient->get('query', $options); + $response = $this->httpClient->get('query'.$params, $options); $raw = (string) $response->getBody(); @@ -180,6 +182,7 @@ class Client public function write($database, $data) { try { + $this->httpClient->post( $this->getBaseURI() . '/write?db=' . $database, array('body' => $data) diff --git a/src/InfluxDB/Database.php b/src/InfluxDB/Database.php index a2a6eb848..470df190b 100644 --- a/src/InfluxDB/Database.php +++ b/src/InfluxDB/Database.php @@ -100,16 +100,21 @@ class Database } } + /** + * @param RetentionPolicy $retentionPolicy + */ public function createRetentionPolicy(RetentionPolicy $retentionPolicy) { $this->query($this->getRetentionPolicyQuery('CREATE', $retentionPolicy)); } /** - * Writes points into INfluxdb + * Writes points into InfluxDB * - * @param Point [] - * @return ResultSet + * @param array $points + * + * @return bool + * @throws Exception */ public function writePoints(array $points) { @@ -118,7 +123,7 @@ class Database foreach ($points as $point) { if (!$point instanceof Point) { - throw new \InvalidArgumentException('Array of Point should be passed'); + throw new \InvalidArgumentException('An array of Point[] should be passed'); } $payload[] = (string) $point; diff --git a/src/InfluxDB/Point.php b/src/InfluxDB/Point.php index 3d8f97009..6567721de 100644 --- a/src/InfluxDB/Point.php +++ b/src/InfluxDB/Point.php @@ -2,6 +2,8 @@ namespace InfluxDB; +use InfluxDB\Database\Exception; + /** * Class Point * @@ -13,30 +15,45 @@ class Point /** * @var array */ - private $tags; + private $tags = array(); /** * @var array */ - private $fields; + private $fields = array(); /** * @var string */ - private $timestamp; + private $timestamp = null; /** * The timestamp is optional. * If you do not specify a timestamp the server’s local timestamp will be used * - * @param $measurement - * @param array $tags - * @param array $fields - * @param string $timestamp + * @param string $measurement Name of the measurement + * @param float $value Value of the measurement + * @param array $tags Array of tags + * @param array $additionalFields Array of optional fields + * @param int $timestamp Optional timestamp + * + * @throws Exception */ - public function __construct($measurement, array $tags, array $fields, $timestamp = '') + public function __construct($measurement, $value, array $tags = array(), array $additionalFields = array(), $timestamp = null) { - $this->measurement = $measurement; + + if (empty($measurement)) { + throw new Exception('Invalid measurement name provided'); + } + + $this->measurement = (string) $measurement; $this->tags = $tags; - $this->fields = $fields; + $this->fields = $additionalFields; + + $this->fields += array('value' => (float) $value); + + if ($timestamp && !$this->isValidTimeStamp($timestamp)) { + throw new Exception(sprintf('%s is not a valid timestamp', $timestamp)); + } + $this->timestamp = $timestamp; } @@ -48,13 +65,20 @@ class Point */ public function __toString() { - return sprintf( - '%s,%s %s %s', - $this->measurement, - $this->arrayToString($this->tags), - $this->arrayToString($this->fields), - $this->timestamp - ); + + $string = $this->measurement; + + if (count($this->tags) > 0) { + $string .= ',' . $this->arrayToString($this->tags); + } + + $string .= ' ' .$this->arrayToString($this->fields); + + if ($this->timestamp) { + $string .= ' '.$this->timestamp; + } + + return $string; } private function arrayToString(array $arr) @@ -68,4 +92,15 @@ class Point return implode(",", $strParts); } + /** + * @param $timestamp + * + * @return bool + */ + private function isValidTimeStamp($timestamp) + { + return ((int) $timestamp === $timestamp) + && ($timestamp <= PHP_INT_MAX) + && ($timestamp >= ~PHP_INT_MAX); + } } \ No newline at end of file diff --git a/src/InfluxDB/Query/Builder.php b/src/InfluxDB/Query/Builder.php index 96865025d..4792f299e 100644 --- a/src/InfluxDB/Query/Builder.php +++ b/src/InfluxDB/Query/Builder.php @@ -20,6 +20,9 @@ use InfluxDB\ResultSet; * * $series->select('*')->from('*')->getResult(); * + * @todo add inner join + * @todo add merge + * * @package InfluxDB\Query */ class Builder @@ -31,6 +34,7 @@ class Builder protected $startTime = null; protected $endTime = null; protected $metric = null; + protected $limitClause = ''; /** * @param Database $db @@ -190,25 +194,34 @@ class Builder } /** - * Gets the result from the database (builds the query) + * Limit the ResultSet to n records * - * @param bool $raw always return the ResultSeriesObjects, even when using an aggregation function + * @param int $count + * + * @return $this + */ + public function limit($count) + { + $this->limitClause = sprintf(' LIMIT %s', (int) $count); + + return $this; + } + +// public function orderBy + + /** + * Gets the result from the database (builds the query) * * @return ResultSet */ - public function getResultSet($raw = false) + public function getResultSet() { $query = sprintf("SELECT %s FROM %s", $this->selection, $this->metric); - $aggregateKey = null; if (!$this->metric) { throw new \InvalidArgumentException('No metric provided to from()'); } - if (preg_match("/([a-z]+)\(/i", $this->selection, $matches)) { - $aggregateKey = $matches[1]; - } - for ($i=0; $i < count($this->where); $i++) { $selection = 'WHERE'; if ($i > 0) { @@ -220,6 +233,10 @@ class Builder } + if ($this->limitClause) { + $query .= $this->limitClause; + } + return $this->db->query($query); } } \ No newline at end of file diff --git a/src/InfluxDB/ResultSet.php b/src/InfluxDB/ResultSet.php index d8ca020da..39516a978 100644 --- a/src/InfluxDB/ResultSet.php +++ b/src/InfluxDB/ResultSet.php @@ -92,7 +92,7 @@ class ResultSet throw new ClientException($object['error']); } - return $object['series']; + return (isset($object['series']) ? $object['series'] : array()); }; // Foreach object, pick series key diff --git a/tests/unit/DatabaseTest.php b/tests/unit/DatabaseTest.php index a351e8031..ab328dae1 100644 --- a/tests/unit/DatabaseTest.php +++ b/tests/unit/DatabaseTest.php @@ -38,15 +38,15 @@ class DatabaseTest extends \PHPUnit_Framework_TestCase { $point1 = new Point( 'cpu_load_short', - array('host' =>'server01', 'region'=>'us-west'), - array('value' => 0.64), - 'myTime' + 0.64, + array('host' => 'server01', 'region' => 'us-west'), + array('cpucount' => 10), + 1435222310 ); + $point2 = new Point( 'cpu_load_short', - array('host' =>'server01', 'region'=>'us-west'), - array('value' => 0.84), - 'myTime' + 0.84 ); $payloadExpected ="$point1\n$point2"; diff --git a/tests/unit/PointTest.php b/tests/unit/PointTest.php index d57713b37..eaee63fe7 100644 --- a/tests/unit/PointTest.php +++ b/tests/unit/PointTest.php @@ -15,13 +15,14 @@ class PointTest extends \PHPUnit_Framework_TestCase { public function testPointStringRepresentation() { - $expected = 'cpu_load_short,host=server01,region=us-west value=0.64 myTime'; + $expected = 'cpu_load_short,host=server01,region=us-west cpucount=10,value=0.64 1435222310'; - $point = new Point( + $point = new Point( 'cpu_load_short', - array('host' =>'server01', 'region'=>'us-west'), - array('value' => 0.64), - 'myTime' + 0.64, + array('host' => 'server01', 'region' => 'us-west'), + array('cpucount' => 10), + 1435222310 ); $this->assertEquals($expected, (string) $point); From 4b5e070e0a6bd1d4688de2e529383a2acce74ead Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 25 Jun 2015 11:51:15 +0200 Subject: [PATCH 28/72] Typo fix readme.md --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2ab4bfc51..28e4cb88f 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,9 @@ It's also possible to create a client from a DSN: $database = InfluxDB\Client::fromDSN(sprintf('influxdb://user:pass@%s:%s/%s', $host, $port, $dbname)); // get the client to retrieve other databases - $client = $database->getClient(); -```php + $client = $database->getClient(); + +``` ### Reading @@ -52,7 +53,8 @@ It's also possible to use the QueryBuilder object. This is a class that simplifi ->select('cpucount') ->from('test_metric') ->limit(2) - ->getResultSet()->getPoints(); + ->getResultSet() + ->getPoints(); ``` ### Writing data @@ -130,6 +132,6 @@ Some functions are too general for a database. So these are available in the cli ## Changelog -0.1 +####0.1 ------ -Initial release \ No newline at end of file +* Initial release \ No newline at end of file From fe1d902d3925ddf2d950ab4e33c5b2be1d45e2f1 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 25 Jun 2015 11:56:54 +0200 Subject: [PATCH 29/72] Fixed overhead with array iteration --- src/InfluxDB/ResultSet.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/InfluxDB/ResultSet.php b/src/InfluxDB/ResultSet.php index 39516a978..fc86db88f 100644 --- a/src/InfluxDB/ResultSet.php +++ b/src/InfluxDB/ResultSet.php @@ -59,8 +59,9 @@ class ResultSet public function getPoints($metricName = '', array $tags = array()) { $points = array(); + $series = $this->getSeries(); - foreach ($this->getSeries() as $serie) { + foreach ($series as $serie) { if ((empty($metricName) && empty($tags) || $serie['name'] == $metricName From abe1492b852e6b140013e8838932b0e444c13490 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 25 Jun 2015 16:31:04 +0200 Subject: [PATCH 30/72] Fixed unit tests --- .travis.yml | 2 +- src/InfluxDB/ResultSet.php | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8e1ab4ce0..f662d47f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,4 +6,4 @@ php: - 5.6 install: - - composer install \ No newline at end of file + - composer install diff --git a/src/InfluxDB/ResultSet.php b/src/InfluxDB/ResultSet.php index fc86db88f..c6810645c 100644 --- a/src/InfluxDB/ResultSet.php +++ b/src/InfluxDB/ResultSet.php @@ -96,9 +96,11 @@ class ResultSet return (isset($object['series']) ? $object['series'] : array()); }; + // we use array_shift because of compatibility with php5.3 // Foreach object, pick series key + $map = array_map($pickSeries, $this->parsedResults['results']); return array_shift( - array_map($pickSeries, $this->parsedResults['results']) + $map ); } From 963ed464d566b17eef00f2fce3d68b4292acbf0d Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 25 Jun 2015 18:04:12 +0200 Subject: [PATCH 31/72] Ensured support for php 5.3 by changing the guzzle client to 3.* --- README.md | 10 ++ composer.json | 2 +- composer.lock | 195 +++++++++++++-------------------- src/InfluxDB/Client.php | 37 +++---- src/InfluxDB/Query/Builder.php | 19 +++- 5 files changed, 120 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index 28e4cb88f..9507bdba3 100644 --- a/README.md +++ b/README.md @@ -49,12 +49,22 @@ To fetch records from InfluxDB you can do a query directly on a database: It's also possible to use the QueryBuilder object. This is a class that simplifies the process of building queries. ```php + + // retrieve points with the query builder $result = $database->getQueryBuilder() ->select('cpucount') ->from('test_metric') ->limit(2) ->getResultSet() ->getPoints(); + + + // get the query from the QueryBuilder + $query = $database->getQueryBuilder() + ->select('cpucount') + ->from('test_metric') + ->getQuery(); + ``` ### Writing data diff --git a/composer.json b/composer.json index 73f3b4f75..6903916d6 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ ], "require": { "php": ">=5.3", - "guzzlehttp/guzzle": "~5.0" + "guzzlehttp/guzzle": "~3.0" }, "scripts": { "post-install-cmd": [ diff --git a/composer.lock b/composer.lock index 0a9d8afcd..c5bb4ba85 100644 --- a/composer.lock +++ b/composer.lock @@ -4,34 +4,70 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "10abd66a90e1473453cbda87799ed079", + "hash": "bdd93bffe0aad03c6421d5d171d6b8c3", "packages": [ { "name": "guzzlehttp/guzzle", - "version": "5.3.x-dev", + "version": "v3.8.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "fd861570a9c3c28d98f418feea1f43f6268bdfa0" + "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/fd861570a9c3c28d98f418feea1f43f6268bdfa0", - "reference": "fd861570a9c3c28d98f418feea1f43f6268bdfa0", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/4de0618a01b34aa1c8c33a3f13f396dcd3882eba", + "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba", "shasum": "" }, "require": { - "guzzlehttp/ringphp": "^1.1", - "php": ">=5.4.0" + "ext-curl": "*", + "php": ">=5.3.3", + "symfony/event-dispatcher": ">=2.1" + }, + "replace": { + "guzzle/batch": "self.version", + "guzzle/cache": "self.version", + "guzzle/common": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version", + "guzzle/iterator": "self.version", + "guzzle/log": "self.version", + "guzzle/parser": "self.version", + "guzzle/plugin": "self.version", + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-error-response": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version", + "guzzle/service": "self.version", + "guzzle/stream": "self.version" }, "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "^4.0" + "doctrine/cache": "*", + "monolog/monolog": "1.*", + "phpunit/phpunit": "3.7.*", + "psr/log": "1.0.*", + "symfony/class-loader": "*", + "zendframework/zend-cache": "<2.3", + "zendframework/zend-log": "<2.3" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.8-dev" + } + }, "autoload": { - "psr-4": { - "GuzzleHttp\\": "src/" + "psr-0": { + "Guzzle": "src/", + "Guzzle\\Tests": "tests/" } }, "notification-url": "https://packagist.org/downloads/", @@ -43,6 +79,10 @@ "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "Guzzle Community", + "homepage": "https://github.com/guzzle/guzzle/contributors" } ], "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", @@ -56,78 +96,36 @@ "rest", "web service" ], - "time": "2015-06-03 05:11:42" + "time": "2014-01-28 22:29:15" }, { - "name": "guzzlehttp/ringphp", + "name": "symfony/event-dispatcher", "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/guzzle/RingPHP.git", - "reference": "9465032ac5d6beaa55f10923403e6e1c36018d9c" + "url": "https://github.com/symfony/EventDispatcher.git", + "reference": "f991afd968ea05582bae203754d761714598d018" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/9465032ac5d6beaa55f10923403e6e1c36018d9c", - "reference": "9465032ac5d6beaa55f10923403e6e1c36018d9c", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/f991afd968ea05582bae203754d761714598d018", + "reference": "f991afd968ea05582bae203754d761714598d018", "shasum": "" }, "require": { - "guzzlehttp/streams": "~3.0", - "php": ">=5.4.0", - "react/promise": "~2.0" + "php": ">=5.5.9" }, "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "~4.0" + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/dependency-injection": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/phpunit-bridge": "~2.8|~3.0", + "symfony/stopwatch": "~2.8|~3.0" }, "suggest": { - "ext-curl": "Guzzle will use specific adapters if cURL is present" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Ring\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.", - "time": "2015-05-21 17:23:02" - }, - { - "name": "guzzlehttp/streams", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/guzzle/streams.git", - "reference": "d1f8a6c55f0f753cfd6f6755856473eb02cedb19" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/streams/zipball/d1f8a6c55f0f753cfd6f6755856473eb02cedb19", - "reference": "d1f8a6c55f0f753cfd6f6755856473eb02cedb19", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" + "symfony/dependency-injection": "", + "symfony/http-kernel": "" }, "type": "library", "extra": { @@ -137,7 +135,7 @@ }, "autoload": { "psr-4": { - "GuzzleHttp\\Stream\\": "src/" + "Symfony\\Component\\EventDispatcher\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -146,62 +144,17 @@ ], "authors": [ { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Provides a simple abstraction over streams of data", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "Guzzle", - "stream" - ], - "time": "2015-01-22 00:01:34" - }, - { - "name": "react/promise", - "version": "v2.2.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/promise.git", - "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/365fcee430dfa4ace1fbc75737ca60ceea7eeeef", - "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "psr-4": { - "React\\Promise\\": "src/" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ { - "name": "Jan Sorgalla", - "email": "jsorgalla@googlemail.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "A lightweight implementation of CommonJS Promises/A for PHP", - "time": "2014-12-30 13:32:42" + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2015-05-12 15:48:43" } ], "packages-dev": [], diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index 4306ffe7e..6156c7d82 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -6,7 +6,6 @@ namespace InfluxDB; -use GuzzleHttp\Client as httpClient; use InfluxDB\Client\Exception as ClientException; /** @@ -67,7 +66,7 @@ class Client protected $baseURI; /** - * @var \GuzzleHttp\Client + * @var \Guzzle\Http\Client */ protected $httpClient; @@ -114,12 +113,7 @@ class Client // the the base URI $this->setBaseURI(sprintf('%s://%s:%d', $this->scheme, $this->host, $this->port)); - - $this->httpClient = new httpClient(array( - 'base_url' => $this->getBaseURI(), - 'timeout' => $this->getTimeout() - ) - ); + $this->httpClient = new \Guzzle\Http\Client($this->getBaseURI()); } @@ -159,12 +153,12 @@ class Client $params = '?'.http_build_query(array_merge(array('q' => $query), $params)); - $options = array_merge($this->options, array('exceptions' => false)); + $options = array_merge($this->options, array('exceptions' => false, 'timeout' => $this->getTimeout())); try { - $response = $this->httpClient->get('query'.$params, $options); + $response = $this->httpClient->get('query'.$params, null, $options); - $raw = (string) $response->getBody(); + $raw = (string) $response->send()->getBody(); return new ResultSet($raw); @@ -174,24 +168,29 @@ class Client } /** - * @param $database - * @param $data + * Write points to the database + * + * @param string $database + * @param string $data + * * @return bool + * + * @internal Internal method, do not use directly * @throws Exception */ public function write($database, $data) { try { - $this->httpClient->post( - $this->getBaseURI() . '/write?db=' . $database, - array('body' => $data) - ); + $result = $this->httpClient->post($this->getBaseURI() . '/write?db=' . $database, null, $data, + array('timeout' => $this->getTimeout()) + )->send(); + + return $result->getStatusCode() == 204; + } catch (\Exception $e) { throw new Exception(sprintf('Writing has failed, exception: %s', $e->getMessage())); } - - return true; } /** diff --git a/src/InfluxDB/Query/Builder.php b/src/InfluxDB/Query/Builder.php index 4792f299e..1709025f5 100644 --- a/src/InfluxDB/Query/Builder.php +++ b/src/InfluxDB/Query/Builder.php @@ -207,7 +207,14 @@ class Builder return $this; } -// public function orderBy + + /** + * @return string + */ + public function getQuery() + { + return $this->parseQuery(); + } /** * Gets the result from the database (builds the query) @@ -215,6 +222,14 @@ class Builder * @return ResultSet */ public function getResultSet() + { + return $this->db->query($this->parseQuery()); + } + + /** + * @return string + */ + protected function parseQuery() { $query = sprintf("SELECT %s FROM %s", $this->selection, $this->metric); @@ -237,6 +252,6 @@ class Builder $query .= $this->limitClause; } - return $this->db->query($query); + return $query; } } \ No newline at end of file From 2b97c8f187a805b6b175ffe3fc0809d52acf76bb Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 25 Jun 2015 18:16:12 +0200 Subject: [PATCH 32/72] Forced symfony dispatcher dependency to 2.8 --- composer.json | 3 ++- composer.lock | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/composer.json b/composer.json index 6903916d6..3159ba9cc 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,8 @@ ], "require": { "php": ">=5.3", - "guzzlehttp/guzzle": "~3.0" + "guzzlehttp/guzzle": "3.*", + "symfony/event-dispatcher": "2.*" }, "scripts": { "post-install-cmd": [ diff --git a/composer.lock b/composer.lock index c5bb4ba85..af32ca7fa 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "bdd93bffe0aad03c6421d5d171d6b8c3", + "hash": "a6eb628e2e801a1d6843522d3da94713", "packages": [ { "name": "guzzlehttp/guzzle", @@ -100,28 +100,28 @@ }, { "name": "symfony/event-dispatcher", - "version": "dev-master", + "version": "2.8.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "f991afd968ea05582bae203754d761714598d018" + "reference": "d7246885b7fe4cb5a2786bda34362d2f0e40b730" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/f991afd968ea05582bae203754d761714598d018", - "reference": "f991afd968ea05582bae203754d761714598d018", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/d7246885b7fe4cb5a2786bda34362d2f0e40b730", + "reference": "d7246885b7fe4cb5a2786bda34362d2f0e40b730", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.9" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0", - "symfony/dependency-injection": "~2.8|~3.0", - "symfony/expression-language": "~2.8|~3.0", - "symfony/phpunit-bridge": "~2.8|~3.0", - "symfony/stopwatch": "~2.8|~3.0" + "symfony/config": "~2.0,>=2.0.5|~3.0.0", + "symfony/dependency-injection": "~2.6|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", + "symfony/phpunit-bridge": "~2.7|~3.0.0", + "symfony/stopwatch": "~2.3|~3.0.0" }, "suggest": { "symfony/dependency-injection": "", @@ -130,7 +130,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -154,7 +154,7 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2015-05-12 15:48:43" + "time": "2015-06-24 15:32:32" } ], "packages-dev": [], From 04e6c83a52bcfcad5df82a77cec06e475697671b Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 25 Jun 2015 18:19:32 +0200 Subject: [PATCH 33/72] Added travis build badge to README.MD --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9507bdba3..19b6f715e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # influxdb-php ## InfluxDB client library for PHP +[![Build Status](https://travis-ci.org/LeaseWeb/influxdb-php.svg?branch=master)](https://travis-ci.org/LeaseWeb/influxdb-php) ### Overview From 4f01e8a8636302e9c8790279c8b484704f802fa0 Mon Sep 17 00:00:00 2001 From: TheCodeAssassin Date: Thu, 25 Jun 2015 18:24:42 +0200 Subject: [PATCH 34/72] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 19b6f715e..d41011be3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # influxdb-php ## InfluxDB client library for PHP [![Build Status](https://travis-ci.org/LeaseWeb/influxdb-php.svg?branch=master)](https://travis-ci.org/LeaseWeb/influxdb-php) +[![Code Climate](https://codeclimate.com/github/LeaseWeb/influxdb-php/badges/gpa.svg)](https://codeclimate.com/github/LeaseWeb/influxdb-php) ### Overview @@ -145,4 +146,4 @@ Some functions are too general for a database. So these are available in the cli ####0.1 ------ -* Initial release \ No newline at end of file +* Initial release From 2b5fc7b279c57e5ed806f6cccc87cd4b10a80f02 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 25 Jun 2015 23:32:43 +0200 Subject: [PATCH 35/72] Updated readme --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d41011be3..de469559c 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,8 @@ To fetch records from InfluxDB you can do a query directly on a database: ```php + // fetch the db + $database = $client->db('influx_test_db'); // executing a query will yield a resultset object $result = $database->query('select * from test_metric LIMIT 5'); @@ -81,13 +83,15 @@ Writing data is done by providing an array of points to the writePoints method o 'test_metric', 0.64, array('host' => 'server01', 'region' => 'us-west'), - array('cpucount' => 10) + array('cpucount' => 10), + 1435255849 ), new Point( 'test_metric', 0.84, array('host' => 'server01', 'region' => 'us-west'), - array('cpucount' => 10) + array('cpucount' => 10), + 1435255850 ) ) ); @@ -112,6 +116,9 @@ This library makes it easy to provide a retention policy when creating a databas // create the client $client = new \InfluxDB\Client($host, $port, '', ''); + // select the db + $database = $client->db('influx_test_db'); + // create the database with a retention policy $result = $database->create(new RetentionPolicy('test', '5d', 1, true)); From 1bcfebacd5ede6ae648d4e009dd5ae6bc6a0befb Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 25 Jun 2015 23:40:18 +0200 Subject: [PATCH 36/72] Updated keywords in composer.json; --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 3159ba9cc..7512221b5 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,7 @@ { "name": "leaseweb/influxdb-php", "description": "InfluxDB client library for PHP", + "keywords": ["influxdb", "client", "time series" , "influxdb client", "influxdb class", "influxdb library"], "minimum-stability": "dev", "authors": [ { From abd72a5c884720bf60103cfee7be935461904bc7 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Mon, 29 Jun 2015 10:20:47 +0200 Subject: [PATCH 37/72] Added code coverage to travis.yml; performance optimizations --- .travis.yml | 7 + composer.json | 72 +++--- composer.lock | 522 +++++++++++++++++++++++++++++++++++++++- src/InfluxDB/Client.php | 45 ++-- 4 files changed, 580 insertions(+), 66 deletions(-) diff --git a/.travis.yml b/.travis.yml index f662d47f6..658574be2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,3 +7,10 @@ php: install: - composer install + +addons: + code_climate: + repo_token: 57c4c4c0438b86b58a4bbf5e3bcba3065ff66300b75d2569bdf6cab204b9af4a + +after_script: + - vendor/bin/test-reporter \ No newline at end of file diff --git a/composer.json b/composer.json index 7512221b5..ef938be87 100644 --- a/composer.json +++ b/composer.json @@ -1,35 +1,43 @@ { - "name": "leaseweb/influxdb-php", - "description": "InfluxDB client library for PHP", - "keywords": ["influxdb", "client", "time series" , "influxdb client", "influxdb class", "influxdb library"], - "minimum-stability": "dev", - "authors": [ - { - "name": "Stephen Hoogendijk", - "email": "stephen@tca0.nl" - } - ], - "require": { - "php": ">=5.3", - "guzzlehttp/guzzle": "3.*", - "symfony/event-dispatcher": "2.*" - }, - "scripts": { - "post-install-cmd": [ - - ], - "post-update-cmd": [ - - ] - }, - "autoload": { - "psr-4" : { - "InfluxDB\\": "src/InfluxDB" - } - }, - "autoload-dev": { - "psr-4": { - "InfluxDB\\Test\\": "tests" - } + "name": "leaseweb/influxdb-php", + "description": "InfluxDB client library for PHP", + "keywords": [ + "influxdb", + "client", + "time series", + "influxdb client", + "influxdb class", + "influxdb library" + ], + "minimum-stability": "dev", + "authors": [ + { + "name": "Stephen Hoogendijk", + "email": "stephen@tca0.nl" } + ], + "require": { + "php": ">=5.3", + "guzzlehttp/guzzle": "3.*", + "symfony/event-dispatcher": "2.*" + }, + "require-dev": { + "codeclimate/php-test-reporter": "dev-master" + }, + "scripts": { + "post-install-cmd": [ + ], + "post-update-cmd": [ + ] + }, + "autoload": { + "psr-4": { + "InfluxDB\\": "src/InfluxDB" + } + }, + "autoload-dev": { + "psr-4": { + "InfluxDB\\Test\\": "tests" + } + } } diff --git a/composer.lock b/composer.lock index af32ca7fa..f763d3938 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "a6eb628e2e801a1d6843522d3da94713", + "hash": "534e09decc695b11790460256bba5ac3", "packages": [ { "name": "guzzlehttp/guzzle", @@ -157,10 +157,526 @@ "time": "2015-06-24 15:32:32" } ], - "packages-dev": [], + "packages-dev": [ + { + "name": "codeclimate/php-test-reporter", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/codeclimate/php-test-reporter.git", + "reference": "418ae782307841ac50fe26daa4cfe04520b0de9c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/codeclimate/php-test-reporter/zipball/418ae782307841ac50fe26daa4cfe04520b0de9c", + "reference": "418ae782307841ac50fe26daa4cfe04520b0de9c", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3", + "satooshi/php-coveralls": "0.6.*", + "symfony/console": ">=2.0" + }, + "require-dev": { + "ext-xdebug": "*", + "phpunit/phpunit": "3.7.*@stable" + }, + "bin": [ + "composer/bin/test-reporter" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "CodeClimate\\Component": "src/", + "CodeClimate\\Bundle": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Code Climate", + "email": "hello@codeclimate.com", + "homepage": "https://codeclimate.com" + } + ], + "description": "PHP client for reporting test coverage to Code Climate", + "homepage": "https://github.com/codeclimate/php-test-reporter", + "keywords": [ + "codeclimate", + "coverage" + ], + "time": "2015-04-18 14:43:54" + }, + { + "name": "guzzle/guzzle", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle3.git", + "reference": "b3f5050cb6270c7a728a0b74ac2de50a262b3e02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/b3f5050cb6270c7a728a0b74ac2de50a262b3e02", + "reference": "b3f5050cb6270c7a728a0b74ac2de50a262b3e02", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3.3", + "symfony/event-dispatcher": "~2.1" + }, + "replace": { + "guzzle/batch": "self.version", + "guzzle/cache": "self.version", + "guzzle/common": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version", + "guzzle/iterator": "self.version", + "guzzle/log": "self.version", + "guzzle/parser": "self.version", + "guzzle/plugin": "self.version", + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-error-response": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version", + "guzzle/service": "self.version", + "guzzle/stream": "self.version" + }, + "require-dev": { + "doctrine/cache": "~1.3", + "monolog/monolog": "~1.0", + "phpunit/phpunit": "3.7.*", + "psr/log": "~1.0", + "symfony/class-loader": "~2.1", + "zendframework/zend-cache": "2.*,<2.3", + "zendframework/zend-log": "2.*,<2.3" + }, + "suggest": { + "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.9-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle": "src/", + "Guzzle\\Tests": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Guzzle Community", + "homepage": "https://github.com/guzzle/guzzle/contributors" + } + ], + "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2015-04-29 17:06:53" + }, + { + "name": "psr/log", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2012-12-21 11:40:51" + }, + { + "name": "satooshi/php-coveralls", + "version": "v0.6.1", + "source": { + "type": "git", + "url": "https://github.com/satooshi/php-coveralls.git", + "reference": "dd0df95bd37a7cf5c5c50304dfe260ffe4b50760" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/dd0df95bd37a7cf5c5c50304dfe260ffe4b50760", + "reference": "dd0df95bd37a7cf5c5c50304dfe260ffe4b50760", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-simplexml": "*", + "guzzle/guzzle": ">=3.0", + "php": ">=5.3", + "psr/log": "1.0.0", + "symfony/config": ">=2.0", + "symfony/console": ">=2.0", + "symfony/stopwatch": ">=2.2", + "symfony/yaml": ">=2.0" + }, + "require-dev": { + "apigen/apigen": "2.8.*@stable", + "pdepend/pdepend": "dev-master", + "phpmd/phpmd": "dev-master", + "phpunit/php-invoker": ">=1.1.0,<1.2.0", + "phpunit/phpunit": "3.7.*@stable", + "sebastian/finder-facade": "dev-master", + "sebastian/phpcpd": "1.4.*@stable", + "squizlabs/php_codesniffer": "1.4.*@stable", + "theseer/fdomdocument": "dev-master" + }, + "bin": [ + "composer/bin/coveralls" + ], + "type": "library", + "autoload": { + "psr-0": { + "Contrib\\Component": "src/", + "Contrib\\Bundle": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kitamura Satoshi", + "email": "with.no.parachute@gmail.com", + "homepage": "https://www.facebook.com/satooshi.jp" + } + ], + "description": "PHP client library for Coveralls API", + "homepage": "https://github.com/satooshi/php-coveralls", + "keywords": [ + "ci", + "coverage", + "github", + "test" + ], + "time": "2013-05-04 08:07:33" + }, + { + "name": "symfony/config", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/symfony/Config.git", + "reference": "511051bc12a8a49704c19565d05a8377a780cee8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Config/zipball/511051bc12a8a49704c19565d05a8377a780cee8", + "reference": "511051bc12a8a49704c19565d05a8377a780cee8", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/filesystem": "~2.8|~3.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "time": "2015-06-18 16:43:51" + }, + { + "name": "symfony/console", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/symfony/Console.git", + "reference": "6fb9d5a32d3330b9dd598587c52bac6fbca193fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Console/zipball/6fb9d5a32d3330b9dd598587c52bac6fbca193fe", + "reference": "6fb9d5a32d3330b9dd598587c52bac6fbca193fe", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/phpunit-bridge": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2015-06-19 15:19:52" + }, + { + "name": "symfony/filesystem", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/symfony/Filesystem.git", + "reference": "24fc9ecf8ed33772e0744397ba976cae95240a3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Filesystem/zipball/24fc9ecf8ed33772e0744397ba976cae95240a3b", + "reference": "24fc9ecf8ed33772e0744397ba976cae95240a3b", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2015-06-18 16:25:07" + }, + { + "name": "symfony/stopwatch", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/symfony/Stopwatch.git", + "reference": "432f3efeed399ba42f532b86c5ce63eb0fc99a4a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/432f3efeed399ba42f532b86c5ce63eb0fc99a4a", + "reference": "432f3efeed399ba42f532b86c5ce63eb0fc99a4a", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Stopwatch Component", + "homepage": "https://symfony.com", + "time": "2015-06-04 20:30:47" + }, + { + "name": "symfony/yaml", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "1f19f893d8b1e8fb5dc746a0def83a058b8a9983" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/1f19f893d8b1e8fb5dc746a0def83a058b8a9983", + "reference": "1f19f893d8b1e8fb5dc746a0def83a058b8a9983", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2015-06-18 16:25:07" + } + ], "aliases": [], "minimum-stability": "dev", - "stability-flags": [], + "stability-flags": { + "codeclimate/php-test-reporter": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index 6156c7d82..5158f77c5 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -112,7 +112,7 @@ class Client } // the the base URI - $this->setBaseURI(sprintf('%s://%s:%d', $this->scheme, $this->host, $this->port)); + $this->baseURI = sprintf('%s://%s:%d', $this->scheme, $this->host, $this->port); $this->httpClient = new \Guzzle\Http\Client($this->getBaseURI()); } @@ -236,11 +236,10 @@ class Client $connParams = parse_url($dsn); $schemeInfo = explode('+', $connParams['scheme']); $dbName = null; + $modifier = null; + $scheme = $schemeInfo[0]; - if (count($schemeInfo) == 1) { - $modifier = null; - $scheme = $schemeInfo[0]; - } else { + if (isset($schemeInfo[1])) { $modifier = $schemeInfo[0]; $scheme = $schemeInfo[1]; } @@ -250,10 +249,7 @@ class Client } $ssl = ($modifier && $modifier == 'https' ? true : false); - - if ($connParams['path']) { - $dbName = substr($connParams['path'], 1); - } + $dbName = ($connParams['path'] ? substr($connParams['path'], 1) : null); $client = new self( $connParams['host'], @@ -265,12 +261,7 @@ class Client $timeout ); - $return = $client; - if ($dbName) { - $return = $client->db($dbName); - } - - return $return; + return ($dbName ? $client->db($dbName) : $client); } /** * @return mixed @@ -280,14 +271,6 @@ class Client return $this->baseURI; } - /** - * @param mixed $baseURI - */ - public function setBaseURI($baseURI) - { - $this->baseURI = $baseURI; - } - /** * @return int */ @@ -296,14 +279,6 @@ class Client return $this->timeout; } - /** - * @param int $timeout - */ - public function setTimeout($timeout) - { - $this->timeout = $timeout; - } - /** * @param array $points * @@ -319,4 +294,12 @@ class Client return $names; } + + /** + * @return \Guzzle\Http\Client + */ + public function getHttpClient() + { + return $this->httpClient; + } } \ No newline at end of file From 9eaad2925e9f38d231885ec7cd86434ff7a7f014 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Mon, 29 Jun 2015 10:33:49 +0200 Subject: [PATCH 38/72] Updated dev dependencies --- composer.json | 8 ++++- composer.lock | 92 +++++++++++++++++++++++++-------------------------- 2 files changed, 52 insertions(+), 48 deletions(-) diff --git a/composer.json b/composer.json index ef938be87..cada24044 100644 --- a/composer.json +++ b/composer.json @@ -20,9 +20,15 @@ "php": ">=5.3", "guzzlehttp/guzzle": "3.*", "symfony/event-dispatcher": "2.*" + }, "require-dev": { - "codeclimate/php-test-reporter": "dev-master" + "codeclimate/php-test-reporter": "0.*", + "symfony/config": "~2.8", + "symfony/console": "~2.8", + "symfony/filesystem": "~2.8", + "symfony/stopwatch": "~2.8", + "symfony/yaml": "~2.8" }, "scripts": { "post-install-cmd": [ diff --git a/composer.lock b/composer.lock index f763d3938..e26469b28 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "534e09decc695b11790460256bba5ac3", + "hash": "3db2b5749b72a686e2a905c11e313ae4", "packages": [ { "name": "guzzlehttp/guzzle", @@ -419,29 +419,29 @@ }, { "name": "symfony/config", - "version": "dev-master", + "version": "2.8.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/Config.git", - "reference": "511051bc12a8a49704c19565d05a8377a780cee8" + "reference": "cceb1141805d401e6f7d2e0b1365bf6a15917778" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Config/zipball/511051bc12a8a49704c19565d05a8377a780cee8", - "reference": "511051bc12a8a49704c19565d05a8377a780cee8", + "url": "https://api.github.com/repos/symfony/Config/zipball/cceb1141805d401e6f7d2e0b1365bf6a15917778", + "reference": "cceb1141805d401e6f7d2e0b1365bf6a15917778", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/filesystem": "~2.8|~3.0" + "php": ">=5.3.9", + "symfony/filesystem": "~2.3|~3.0.0" }, "require-dev": { - "symfony/phpunit-bridge": "~2.8|~3.0" + "symfony/phpunit-bridge": "~2.7|~3.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -465,30 +465,30 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2015-06-18 16:43:51" + "time": "2015-06-28 18:28:18" }, { "name": "symfony/console", - "version": "dev-master", + "version": "2.8.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/Console.git", - "reference": "6fb9d5a32d3330b9dd598587c52bac6fbca193fe" + "reference": "2a909e48c528c7c9b22caff6ff622c6c69032bfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/6fb9d5a32d3330b9dd598587c52bac6fbca193fe", - "reference": "6fb9d5a32d3330b9dd598587c52bac6fbca193fe", + "url": "https://api.github.com/repos/symfony/Console/zipball/2a909e48c528c7c9b22caff6ff622c6c69032bfc", + "reference": "2a909e48c528c7c9b22caff6ff622c6c69032bfc", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.9" }, "require-dev": { "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/phpunit-bridge": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0" + "symfony/event-dispatcher": "~2.1|~3.0.0", + "symfony/phpunit-bridge": "~2.7|~3.0.0", + "symfony/process": "~2.1|~3.0.0" }, "suggest": { "psr/log": "For using the console logger", @@ -498,7 +498,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -522,32 +522,32 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2015-06-19 15:19:52" + "time": "2015-06-22 16:34:55" }, { "name": "symfony/filesystem", - "version": "dev-master", + "version": "2.8.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/Filesystem.git", - "reference": "24fc9ecf8ed33772e0744397ba976cae95240a3b" + "reference": "5db575c1ad5f62363c098114cf482bbd5d15349a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Filesystem/zipball/24fc9ecf8ed33772e0744397ba976cae95240a3b", - "reference": "24fc9ecf8ed33772e0744397ba976cae95240a3b", + "url": "https://api.github.com/repos/symfony/Filesystem/zipball/5db575c1ad5f62363c098114cf482bbd5d15349a", + "reference": "5db575c1ad5f62363c098114cf482bbd5d15349a", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.9" }, "require-dev": { - "symfony/phpunit-bridge": "~2.8|~3.0" + "symfony/phpunit-bridge": "~2.7|~3.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -571,32 +571,32 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2015-06-18 16:25:07" + "time": "2015-06-18 16:14:27" }, { "name": "symfony/stopwatch", - "version": "dev-master", + "version": "2.8.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/Stopwatch.git", - "reference": "432f3efeed399ba42f532b86c5ce63eb0fc99a4a" + "reference": "a3cf998e50cae3e32e81e401150c7d4b3ecc03d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/432f3efeed399ba42f532b86c5ce63eb0fc99a4a", - "reference": "432f3efeed399ba42f532b86c5ce63eb0fc99a4a", + "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/a3cf998e50cae3e32e81e401150c7d4b3ecc03d5", + "reference": "a3cf998e50cae3e32e81e401150c7d4b3ecc03d5", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.9" }, "require-dev": { - "symfony/phpunit-bridge": "~2.8|~3.0" + "symfony/phpunit-bridge": "~2.7|~3.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -620,32 +620,32 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2015-06-04 20:30:47" + "time": "2015-06-04 20:21:09" }, { "name": "symfony/yaml", - "version": "dev-master", + "version": "2.8.x-dev", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "1f19f893d8b1e8fb5dc746a0def83a058b8a9983" + "reference": "f248a72777f3fec2bcafdce3ccd94086250448e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/1f19f893d8b1e8fb5dc746a0def83a058b8a9983", - "reference": "1f19f893d8b1e8fb5dc746a0def83a058b8a9983", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/f248a72777f3fec2bcafdce3ccd94086250448e1", + "reference": "f248a72777f3fec2bcafdce3ccd94086250448e1", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.9" }, "require-dev": { - "symfony/phpunit-bridge": "~2.8|~3.0" + "symfony/phpunit-bridge": "~2.7|~3.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.8-dev" } }, "autoload": { @@ -669,14 +669,12 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2015-06-18 16:25:07" + "time": "2015-06-19 15:09:14" } ], "aliases": [], "minimum-stability": "dev", - "stability-flags": { - "codeclimate/php-test-reporter": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From 642094b58ad7ae4df41f166b085857141d67eb7a Mon Sep 17 00:00:00 2001 From: Paul Dix Date: Fri, 8 Nov 2013 08:10:41 -0800 Subject: [PATCH 39/72] Initial commit --- LICENSE | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..38ee24919 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 InfluxDB + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From 065fbb4a8c392829eca6716305ed2e38ef416bef Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Fri, 3 Jul 2015 15:41:02 +0200 Subject: [PATCH 40/72] Merged leaseweb/influxdb-php into influxdb/influxdb-php --- CONTRIBUTE.md | 37 ++++++++++++++++++++ README.md | 17 +++++++--- composer.json | 4 +++ src/InfluxDB/Client.php | 12 ++----- src/InfluxDB/Database.php | 4 +-- src/InfluxDB/Point.php | 8 ++--- tests/unit/DatabaseTest.php | 68 +++++++++++++++++++++++++++++++++++-- 7 files changed, 127 insertions(+), 23 deletions(-) create mode 100644 CONTRIBUTE.md diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md new file mode 100644 index 000000000..a71780b0d --- /dev/null +++ b/CONTRIBUTE.md @@ -0,0 +1,37 @@ +/* CONTRIBUTE */ + +This is the contribute.md of influxdb-php. Great to have you here. + +Here are a few ways you can help make this project better. + +# Contribute.md + +## Team members + +Stephen "TheCodeAssassin" Hoogendijk +Daniel "danibrutal" Martinez + +## Helping out + +We appreciate any efforts to help us writing this library. You can contribute in any of the following ways: + +* Documentation +* Unit tests +* New features +* Bug fixed +* Reviewing pull requests + +## Guidelines + +In order for your pull requests to get accepted we hold all the code to the following criteria: + +* PSR-1/PSR-2 compliant +* Do not use left hand conditions such as false == $something +* New features need to be documented +* Breaking changes should be well highlighted and explained in the PR + +The following is optional but encouraged: + +* Code should be documented +* Code should be unit tested +* Do not write conditions like false === $something, rather $something === false. diff --git a/README.md b/README.md index de469559c..9f2e7c460 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ ## InfluxDB client library for PHP [![Build Status](https://travis-ci.org/LeaseWeb/influxdb-php.svg?branch=master)](https://travis-ci.org/LeaseWeb/influxdb-php) [![Code Climate](https://codeclimate.com/github/LeaseWeb/influxdb-php/badges/gpa.svg)](https://codeclimate.com/github/LeaseWeb/influxdb-php) +[![Test Coverage](https://codeclimate.com/github/LeaseWeb/influxdb-php/badges/coverage.svg)](https://codeclimate.com/github/LeaseWeb/influxdb-php/coverage) ### Overview @@ -39,8 +40,8 @@ To fetch records from InfluxDB you can do a query directly on a database: ```php - // fetch the db - $database = $client->db('influx_test_db'); + // fetch the selectDB + $database = $client->selectDB('influx_test_db'); // executing a query will yield a resultset object $result = $database->query('select * from test_metric LIMIT 5'); @@ -116,8 +117,8 @@ This library makes it easy to provide a retention policy when creating a databas // create the client $client = new \InfluxDB\Client($host, $port, '', ''); - // select the db - $database = $client->db('influx_test_db'); + // select the selectDB + $database = $client->selectDB('influx_test_db'); // create the database with a retention policy $result = $database->create(new RetentionPolicy('test', '5d', 1, true)); @@ -151,6 +152,12 @@ Some functions are too general for a database. So these are available in the cli ## Changelog -####0.1 +####0.1.1 +* Merged repository to influxdb/influxdb-php +* Added unit test for createRetentionPolicy +* -BREAKING CHANGE- changed $client->db to $client->selectDB + + +####0.1.0 ------ * Initial release diff --git a/composer.json b/composer.json index cada24044..1f44e1904 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,10 @@ { "name": "Stephen Hoogendijk", "email": "stephen@tca0.nl" + }, + { + "name": "Daniel Martinez", + "email": "danimartcas@hotmail.com" } ], "require": { diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index 5158f77c5..2a7e677e3 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -124,7 +124,7 @@ class Client * * @return Database */ - public function db($name) + public function selectDB($name) { if (empty($name)) { @@ -261,7 +261,7 @@ class Client $timeout ); - return ($dbName ? $client->db($dbName) : $client); + return ($dbName ? $client->selectDB($dbName) : $client); } /** * @return mixed @@ -294,12 +294,4 @@ class Client return $names; } - - /** - * @return \Guzzle\Http\Client - */ - public function getHttpClient() - { - return $this->httpClient; - } } \ No newline at end of file diff --git a/src/InfluxDB/Database.php b/src/InfluxDB/Database.php index 470df190b..660e02e8a 100644 --- a/src/InfluxDB/Database.php +++ b/src/InfluxDB/Database.php @@ -44,7 +44,7 @@ class Database $this->client = $client; if (!$name) { - throw new DatabaseException('No database name provided'); + throw new \InvalidArgumentException('No database name provided'); } $this->name = $name; @@ -105,7 +105,7 @@ class Database */ public function createRetentionPolicy(RetentionPolicy $retentionPolicy) { - $this->query($this->getRetentionPolicyQuery('CREATE', $retentionPolicy)); + return $this->query($this->getRetentionPolicyQuery('CREATE', $retentionPolicy)); } /** diff --git a/src/InfluxDB/Point.php b/src/InfluxDB/Point.php index 6567721de..f6fe43ee2 100644 --- a/src/InfluxDB/Point.php +++ b/src/InfluxDB/Point.php @@ -2,7 +2,7 @@ namespace InfluxDB; -use InfluxDB\Database\Exception; +use InfluxDB\Database\Exception as DatabaseException; /** * Class Point @@ -35,13 +35,13 @@ class Point * @param array $additionalFields Array of optional fields * @param int $timestamp Optional timestamp * - * @throws Exception + * @throws DatabaseException */ public function __construct($measurement, $value, array $tags = array(), array $additionalFields = array(), $timestamp = null) { if (empty($measurement)) { - throw new Exception('Invalid measurement name provided'); + throw new DatabaseException('Invalid measurement name provided'); } $this->measurement = (string) $measurement; @@ -51,7 +51,7 @@ class Point $this->fields += array('value' => (float) $value); if ($timestamp && !$this->isValidTimeStamp($timestamp)) { - throw new Exception(sprintf('%s is not a valid timestamp', $timestamp)); + throw new DatabaseException(sprintf('%s is not a valid timestamp', $timestamp)); } $this->timestamp = $timestamp; diff --git a/tests/unit/DatabaseTest.php b/tests/unit/DatabaseTest.php index ab328dae1..890c03e45 100644 --- a/tests/unit/DatabaseTest.php +++ b/tests/unit/DatabaseTest.php @@ -6,6 +6,8 @@ namespace InfluxDB\Test; use InfluxDB\Client; use InfluxDB\Database; use InfluxDB\Point; +use InfluxDB\ResultSet; +use PHPUnit_Framework_MockObject_MockObject; class DatabaseTest extends \PHPUnit_Framework_TestCase { @@ -13,24 +15,85 @@ class DatabaseTest extends \PHPUnit_Framework_TestCase /** @var Database $db */ protected $db = null; - /** @var Client $client */ + /** @var Client|PHPUnit_Framework_MockObject_MockObject $client */ protected $mockClient; + /** + * @var string + */ protected $dataToInsert; + /** + * @var string + */ + protected $resultData; + + /** + * @var string + */ + static $emptyResult = '{"results":[{}]}'; + + /** + * @var + */ + protected $mockResultSet; + public function setUp() { $this->mockClient = $this->getMockBuilder('\InfluxDB\Client') ->disableOriginalConstructor() ->getMock(); + $this->resultData = file_get_contents(dirname(__FILE__) . '/result.example.json'); + $this->mockClient->expects($this->any()) ->method('getBaseURI') ->will($this->returnValue($this->equalTo('http://localhost:8086'))); + $this->mockClient->expects($this->any()) + ->method('query') + ->will($this->returnValue(new ResultSet($this->resultData))); + $this->db = new Database('influx_test_db', $this->mockClient); $this->dataToInsert = file_get_contents(dirname(__FILE__) . '/input.example.json'); + + } + + /** + * + */ + public function testQuery() + { + $testResultSet = new ResultSet($this->resultData); + $this->assertEquals($this->db->query('SELECT * FROM test_metric'), $testResultSet); + } + + public function testCreateRetentionPolicy() + { + $retentionPolicy = new Database\RetentionPolicy('test', '1d', 1, true); + + $mockClient = $this->getMockBuilder('\InfluxDB\Client') + ->disableOriginalConstructor() + ->getMock(); + + $mockClient->expects($this->once()) + ->method('query') + ->will($this->returnValue(new ResultSet(self::$emptyResult))); + + + + $database = new Database('test', $mockClient); + + $this->assertEquals($database->createRetentionPolicy($retentionPolicy), new ResultSet(self::$emptyResult)); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testEmptyDatabaseName() + { + new Database(null, $this->mockClient); } @@ -53,7 +116,8 @@ class DatabaseTest extends \PHPUnit_Framework_TestCase $this->mockClient->expects($this->once()) ->method('write') - ->with($this->equalTo($this->db->getName()), $this->equalTo($payloadExpected)); + ->with($this->equalTo($this->db->getName()), $this->equalTo($payloadExpected)) + ->will($this->returnValue(true)); $this->db->writePoints(array($point1, $point2)); } From de12f7f6c0280750d155f86dcc117b1ad08a2968 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Fri, 3 Jul 2015 15:50:46 +0200 Subject: [PATCH 41/72] Corrected readme, composer.json and license file --- LICENSE.md | 201 -------------------------------------------------- README.md | 11 +-- composer.json | 2 +- 3 files changed, 7 insertions(+), 207 deletions(-) delete mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md deleted file mode 100644 index 27f048ee6..000000000 --- a/LICENSE.md +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2015 LeaseWeb Technologies B.V. - - Licensed 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. \ No newline at end of file diff --git a/README.md b/README.md index 9f2e7c460..e809efad2 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,12 @@ This library was created to have php port of the python influxdb client. This way there will be a common abstraction library between different programming languages. +### Installation + +Installation can be done with composer: + +composer require influxdb/influxdb-php:dev-master + ### Getting started Initialize a new client object: @@ -156,8 +162,3 @@ Some functions are too general for a database. So these are available in the cli * Merged repository to influxdb/influxdb-php * Added unit test for createRetentionPolicy * -BREAKING CHANGE- changed $client->db to $client->selectDB - - -####0.1.0 ------- -* Initial release diff --git a/composer.json b/composer.json index 1f44e1904..eae2c469e 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "leaseweb/influxdb-php", + "name": "influxdb/influxdb-php", "description": "InfluxDB client library for PHP", "keywords": [ "influxdb", From a054bce98dc8d3f71115083dc5b1d1ee075fe22c Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Fri, 3 Jul 2015 16:04:40 +0200 Subject: [PATCH 42/72] Updated readme with todo list --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index e809efad2..aeddab3f5 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,16 @@ Some functions are too general for a database. So these are available in the cli $result = $client->listDatabases(); ``` +## Todo + +* Add UDP support +* Add more admin features +* More unit tests +* Increase documentation (wiki?) +* Add more features to the query builder +* Add validation to RetentionPolicy + + ## Changelog ####0.1.1 From 06b46debefdeae57840a650b451c8cb449df6276 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Fri, 3 Jul 2015 16:08:32 +0200 Subject: [PATCH 43/72] Corrected documentation and added more examples --- README.md | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index aeddab3f5..9c93f805f 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ To fetch records from InfluxDB you can do a query directly on a database: ```php - // fetch the selectDB + // fetch the database $database = $client->selectDB('influx_test_db'); // executing a query will yield a resultset object @@ -84,24 +84,25 @@ Writing data is done by providing an array of points to the writePoints method o ```php - $newPoints = $database->writePoints( - array( - new Point( - 'test_metric', - 0.64, - array('host' => 'server01', 'region' => 'us-west'), - array('cpucount' => 10), - 1435255849 - ), - new Point( - 'test_metric', - 0.84, - array('host' => 'server01', 'region' => 'us-west'), - array('cpucount' => 10), - 1435255850 - ) + // create an array of points + $points = array( + new Point( + 'test_metric', + 0.64, + array('host' => 'server01', 'region' => 'us-west'), + array('cpucount' => 10), + 1435255849 + ), + new Point( + 'test_metric', + 0.84, + array('host' => 'server01', 'region' => 'us-west'), + array('cpucount' => 10), + 1435255850 ) ); + + $newPoints = $database->writePoints($points); ``` @@ -123,7 +124,7 @@ This library makes it easy to provide a retention policy when creating a databas // create the client $client = new \InfluxDB\Client($host, $port, '', ''); - // select the selectDB + // select the database $database = $client->selectDB('influx_test_db'); // create the database with a retention policy @@ -143,6 +144,12 @@ and list them: $result = $database->listRetentionPolicies(); ``` +You can add more retention policies to a database: + +```php + $result = $database->createRetentionPolicy(new RetentionPolicy('test2', '30d', 1, true)); +``` + ### Client functions Some functions are too general for a database. So these are available in the client: From a29f2e51341f6d813e524fe4cf46576b06cede0b Mon Sep 17 00:00:00 2001 From: danibrutal Date: Fri, 3 Jul 2015 17:20:35 +0200 Subject: [PATCH 44/72] Adding Client tests --- tests/unit/ClientTest.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/unit/ClientTest.php b/tests/unit/ClientTest.php index 918d60df6..eee382698 100644 --- a/tests/unit/ClientTest.php +++ b/tests/unit/ClientTest.php @@ -9,12 +9,13 @@ class ClientTest extends \PHPUnit_Framework_TestCase /** @var Client $client */ protected $client = null; - - + public function testBaseURl() { - $this->assertTrue( - true + $client = new Client('localhost', 8086); + + $this->assertEquals( + $client->getBaseURI(), 'http://localhost:8086' ); } } \ No newline at end of file From f6be9bedb47ff82414b17165e68fe712cc9a5d02 Mon Sep 17 00:00:00 2001 From: danibrutal Date: Fri, 3 Jul 2015 17:29:25 +0200 Subject: [PATCH 45/72] Client tests --- tests/unit/ClientTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/unit/ClientTest.php b/tests/unit/ClientTest.php index eee382698..609bb632d 100644 --- a/tests/unit/ClientTest.php +++ b/tests/unit/ClientTest.php @@ -18,4 +18,16 @@ class ClientTest extends \PHPUnit_Framework_TestCase $client->getBaseURI(), 'http://localhost:8086' ); } + + public function testSelectDbShouldReturnDatabaseInstance() + { + $client = new Client('localhost', 8086); + + $dbName = 'test-database'; + $db = $client->selectDB($dbName); + + $this->assertInstanceOf('\InfluxDB\Database', $db); + + $this->assertEquals($dbName, $db->getName()); + } } \ No newline at end of file From 9dc122dccdf3bf68b74750921e9ceae68e68e64b Mon Sep 17 00:00:00 2001 From: danibrutal Date: Mon, 6 Jul 2015 15:58:29 +0200 Subject: [PATCH 46/72] Tests - ClientTest query method --- src/InfluxDB/Client.php | 12 ++++++++++++ tests/unit/ClientTest.php | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index 2a7e677e3..0aa51dff4 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -117,6 +117,18 @@ class Client } + /** + * For testing + * @param \Guzzle\Http\Client $client + * @return $this + */ + public function setHttpClient(\Guzzle\Http\Client $client) + { + $this->httpClient = $client; + + return $this; + } + /** * Use the given database * diff --git a/tests/unit/ClientTest.php b/tests/unit/ClientTest.php index 609bb632d..9240195d5 100644 --- a/tests/unit/ClientTest.php +++ b/tests/unit/ClientTest.php @@ -3,6 +3,7 @@ namespace InfluxDB\Test; use InfluxDB\Client; +use InfluxDB\ResultSet; class ClientTest extends \PHPUnit_Framework_TestCase { @@ -30,4 +31,38 @@ class ClientTest extends \PHPUnit_Framework_TestCase $this->assertEquals($dbName, $db->getName()); } + + + /** + */ + public function testQuery() + { + $client = new Client('localhost', 8086); + $query = "some-bad-query"; + + $bodyResponse = file_get_contents(dirname(__FILE__) . '/result.example.json'); + $httpMockClient = $this->buildHttpMockClient($bodyResponse); + + $client->setHttpClient($httpMockClient); + + /** @var \InfluxDB\ResultSet $result */ + $result = $client->query(null, $query); + + $this->assertInstanceOf('\InfluxDB\ResultSet', $result); + } + + /** + * @return \Guzzle\Http\Client + */ + protected function buildHttpMockClient($body) + { + $plugin = new \Guzzle\Plugin\Mock\MockPlugin(); + $response= new \Guzzle\Http\Message\Response(200); + $response->setBody($body); + $plugin->addResponse($response); + $mockedClient = new \Guzzle\Http\Client(); + $mockedClient->addSubscriber($plugin); + + return $mockedClient; + } } \ No newline at end of file From 5d502dc3b11fd029f47a8615d067fb413c5d3a80 Mon Sep 17 00:00:00 2001 From: TheCodeAssassin Date: Wed, 8 Jul 2015 14:44:27 +0200 Subject: [PATCH 47/72] Updated CI and CodeClimate links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9c93f805f..8b7bb26ba 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # influxdb-php ## InfluxDB client library for PHP -[![Build Status](https://travis-ci.org/LeaseWeb/influxdb-php.svg?branch=master)](https://travis-ci.org/LeaseWeb/influxdb-php) -[![Code Climate](https://codeclimate.com/github/LeaseWeb/influxdb-php/badges/gpa.svg)](https://codeclimate.com/github/LeaseWeb/influxdb-php) -[![Test Coverage](https://codeclimate.com/github/LeaseWeb/influxdb-php/badges/coverage.svg)](https://codeclimate.com/github/LeaseWeb/influxdb-php/coverage) +[![Build Status](https://travis-ci.org/influxdb/influxdb-php.svg?branch=master)](https://travis-ci.org/LeaseWeb/influxdb-php) +[![Code Climate](https://codeclimate.com/github/influxdb/influxdb-php/badges/gpa.svg)](https://codeclimate.com/github/LeaseWeb/influxdb-php) +[![Test Coverage](https://codeclimate.com/github/influxdb/influxdb-php/badges/coverage.svg)](https://codeclimate.com/github/LeaseWeb/influxdb-php/coverage) ### Overview From e40421356b47c4475e5c45f6a1fbf9559e7bf8b7 Mon Sep 17 00:00:00 2001 From: TheCodeAssassin Date: Wed, 8 Jul 2015 15:11:08 +0200 Subject: [PATCH 48/72] Updated links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8b7bb26ba..8b018bc4f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # influxdb-php ## InfluxDB client library for PHP -[![Build Status](https://travis-ci.org/influxdb/influxdb-php.svg?branch=master)](https://travis-ci.org/LeaseWeb/influxdb-php) -[![Code Climate](https://codeclimate.com/github/influxdb/influxdb-php/badges/gpa.svg)](https://codeclimate.com/github/LeaseWeb/influxdb-php) -[![Test Coverage](https://codeclimate.com/github/influxdb/influxdb-php/badges/coverage.svg)](https://codeclimate.com/github/LeaseWeb/influxdb-php/coverage) +[![Build Status](https://travis-ci.org/influxdb/influxdb-php.svg?branch=master)](https://travis-ci.org/influxdb/influxdb-php) +[![Code Climate](https://codeclimate.com/github/influxdb/influxdb-php/badges/gpa.svg)](https://codeclimate.com/github/influxdb/influxdb-php) +[![Test Coverage](https://codeclimate.com/github/influxdb/influxdb-php/badges/coverage.svg)](https://codeclimate.com/github/influxdb/influxdb-php/coverage) ### Overview From 752a20a8a0ba2fad0741102d99ee08ff51e174e1 Mon Sep 17 00:00:00 2001 From: TheCodeAssassin Date: Wed, 8 Jul 2015 15:12:01 +0200 Subject: [PATCH 49/72] updated code climate repo token --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 658574be2..2fbeca661 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ install: addons: code_climate: - repo_token: 57c4c4c0438b86b58a4bbf5e3bcba3065ff66300b75d2569bdf6cab204b9af4a + repo_token: 5371d86d298d66eb9007cc8de462d7063e58f6dd85e430928834736edee479a9 after_script: - - vendor/bin/test-reporter \ No newline at end of file + - vendor/bin/test-reporter From 33a7ea7d62d859b60b0948dfc4e864d0a82faa4a Mon Sep 17 00:00:00 2001 From: TheCodeAssassin Date: Mon, 20 Jul 2015 09:47:28 +0200 Subject: [PATCH 50/72] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8b018bc4f..75f457e3e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,9 @@ ### Overview -This library was created to have php port of the python influxdb client. +A easy to use library for using InfluxDB with PHP. + +The influxdb-php library was created to have php port of the python influxdb client. This way there will be a common abstraction library between different programming languages. ### Installation From fd80291e151c4eba966f85165082fc920c111670 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Mon, 20 Jul 2015 12:22:39 +0200 Subject: [PATCH 51/72] Added precision; added database exists method --- README.md | 31 ++++++++++++++++++++++++++----- src/InfluxDB/Client.php | 8 ++++++-- src/InfluxDB/Database.php | 30 +++++++++++++++++++++++++++--- tests/unit/DatabaseTest.php | 23 ++++++++++++++++++++++- 4 files changed, 81 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 75f457e3e..d8c0ea9b0 100644 --- a/README.md +++ b/README.md @@ -93,26 +93,43 @@ Writing data is done by providing an array of points to the writePoints method o 0.64, array('host' => 'server01', 'region' => 'us-west'), array('cpucount' => 10), - 1435255849 + 1435255849 // Time precision has to be set to seconds! ), new Point( 'test_metric', 0.84, array('host' => 'server01', 'region' => 'us-west'), array('cpucount' => 10), - 1435255850 + 1435255850 // Time precision has to be set to seconds! ) ); - $newPoints = $database->writePoints($points); + // we are writing unix timestamps, which have a second precision + $newPoints = $database->writePoints($points, Database::PRECISION_SECONDS); ``` +It's possible to add multiple [fields](https://influxdb.com/docs/v0.9/concepts/key_concepts.html) when writing +measurements to InfluxDB. The point class allows one to easily write data in batches to influxDB. + The name of a measurement and the value are mandatory. Additional fields, tags and a timestamp are optional. InfluxDB takes the current time as the default timestamp. -It's possible to add multiple [fields](https://influxdb.com/docs/v0.9/concepts/key_concepts.html) when writing -measurements to InfluxDB. The point class allows one to easily write data in batches to influxDB. +#### Timestamp precision + +It's important to provide the correct precision when adding a timestamp to a Point object. This is because +if you specify a timestamp in seconds and the default (nanosecond) precision is set; the entered timestamp will be invalid. + +```php + // Points will require a nanosecond precision (this is default as per influxdb standard) + $newPoints = $database->writePoints($points); + + // Points will require second precision + $newPoints = $database->writePoints($points, Database::PRECISION_SECONDS); + + // Points will require microsecond precision + $newPoints = $database->writePoints($points, Database::PRECISION_MICROSECONDS); +``` ### Creating databases @@ -177,6 +194,10 @@ Some functions are too general for a database. So these are available in the cli ## Changelog +####0.1.2 +* Added exists method to Database class +* Added time precision to database class + ####0.1.1 * Merged repository to influxdb/influxdb-php * Added unit test for createRetentionPolicy diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index 0aa51dff4..694309fce 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -184,17 +184,21 @@ class Client * * @param string $database * @param string $data + * @param string $precision The timestamp precision * * @return bool * * @internal Internal method, do not use directly * @throws Exception */ - public function write($database, $data) + public function write($database, $data, $precision) { try { - $result = $this->httpClient->post($this->getBaseURI() . '/write?db=' . $database, null, $data, + $result = $this->httpClient->post($this->getBaseURI() + . '/write?db=' . $database + . '&precision=' . $precision + , null, $data, array('timeout' => $this->getTimeout()) )->send(); diff --git a/src/InfluxDB/Database.php b/src/InfluxDB/Database.php index 660e02e8a..f5d58d78a 100644 --- a/src/InfluxDB/Database.php +++ b/src/InfluxDB/Database.php @@ -31,6 +31,17 @@ class Database */ protected $client; + + /** + * Precision constants + */ + const PRECISION_NANOSECONDS = 'n'; + const PRECISION_MICROSECONDS = 'u'; + const PRECISION_MILLISECONDS = 'ms'; + const PRECISION_SECONDS = 's'; + const PRECISION_MINUTES = 'm'; + const PRECISION_HOURS = 'h'; + /** * Construct a database object * @@ -102,6 +113,8 @@ class Database /** * @param RetentionPolicy $retentionPolicy + * + * @return ResultSet */ public function createRetentionPolicy(RetentionPolicy $retentionPolicy) { @@ -111,12 +124,13 @@ class Database /** * Writes points into InfluxDB * - * @param array $points + * @param Point[] $points Array of points + * @param string $precision The timestamp precision (defaults to nanoseconds) * * @return bool * @throws Exception */ - public function writePoints(array $points) + public function writePoints(array $points, $precision = self::PRECISION_NANOSECONDS) { $payload = array(); @@ -129,7 +143,17 @@ class Database $payload[] = (string) $point; } - return $this->client->write($this->name, implode(PHP_EOL, $payload)); + return $this->client->write($this->name, implode(PHP_EOL, $payload), $precision); + } + + /** + * @return bool + */ + public function exists() + { + $databases = $this->client->listDatabases(); + + return in_array($this->name, $databases); } /** diff --git a/tests/unit/DatabaseTest.php b/tests/unit/DatabaseTest.php index 890c03e45..1b16f598f 100644 --- a/tests/unit/DatabaseTest.php +++ b/tests/unit/DatabaseTest.php @@ -8,8 +8,9 @@ use InfluxDB\Database; use InfluxDB\Point; use InfluxDB\ResultSet; use PHPUnit_Framework_MockObject_MockObject; +use PHPUnit_Framework_TestCase; -class DatabaseTest extends \PHPUnit_Framework_TestCase +class DatabaseTest extends PHPUnit_Framework_TestCase { /** @var Database $db */ @@ -54,6 +55,12 @@ class DatabaseTest extends \PHPUnit_Framework_TestCase ->method('query') ->will($this->returnValue(new ResultSet($this->resultData))); + + $this->mockClient->expects($this->any()) + ->method('listDatabases') + ->will($this->returnValue(array('test123', 'test'))); + + $this->db = new Database('influx_test_db', $this->mockClient); $this->dataToInsert = file_get_contents(dirname(__FILE__) . '/input.example.json'); @@ -96,6 +103,20 @@ class DatabaseTest extends \PHPUnit_Framework_TestCase new Database(null, $this->mockClient); } + public function testExists() + { + $database = new Database('test', $this->mockClient); + + $this->assertEquals($database->exists(), true); + } + + + public function testNotExists() + { + $database = new Database('test_not_exists', $this->mockClient); + + $this->assertEquals($database->exists(), false); + } public function testWritePointsInASingleCall() { From a790aa49619a0d8bcfdf48e25ee1772f941b0771 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Mon, 20 Jul 2015 15:53:06 +0200 Subject: [PATCH 52/72] Style fixes and removal of redundant check --- src/InfluxDB/Client.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index 694309fce..947622984 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -138,11 +138,6 @@ class Client */ public function selectDB($name) { - - if (empty($name)) { - throw new \InvalidArgumentException(sprintf('No name provided')); - } - return new Database($name, $this); } @@ -156,11 +151,11 @@ class Client * @return ResultSet * @throws Exception */ - public function query($database = null, $query, $params = array()) + public function query($database, $query, $params = array()) { if ($database) { - $params += array('db' => $database); + $params['db'] = $database; } $params = '?'.http_build_query(array_merge(array('q' => $query), $params)); From e36ab876d5b62b6d644209264ba2ac34ceacb119 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 20 Jul 2015 09:28:47 -0300 Subject: [PATCH 53/72] Few tweaks on CS --- src/InfluxDB/Client.php | 89 ++++++++++------------- src/InfluxDB/Client/Exception.php | 3 +- src/InfluxDB/Database.php | 52 ++++--------- src/InfluxDB/Database/Exception.php | 10 +-- src/InfluxDB/Database/RetentionPolicy.php | 17 ++--- src/InfluxDB/Exception.php | 10 +-- src/InfluxDB/Point.php | 68 +++++++++++------ src/InfluxDB/Query/Builder.php | 76 +++++++++++-------- src/InfluxDB/Query/Exception.php | 10 +-- src/InfluxDB/ResultSet.php | 63 ++++++---------- 10 files changed, 186 insertions(+), 212 deletions(-) diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index 947622984..bc87b5bdb 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -1,17 +1,14 @@ host = $host; - $this->port = (int) $port; - $this->username = $username; - $this->password = $password; - $this->timeout = $timeout; + ) { + $this->host = (string) $host; + $this->port = (int) $port; + $this->username = (string) $username; + $this->password = (string) $password; + $this->timeout = (int) $timeout; $this->verifySSL = (bool) $verifySSL; if ($ssl) { $this->scheme = 'https'; - $this->options += array( - 'verify' => $verifySSL - ); + $this->options += array('verify' => $verifySSL); } // the the base URI @@ -119,7 +112,8 @@ class Client /** * For testing - * @param \Guzzle\Http\Client $client + * + * @param \Guzzle\Http\Client $client * @return $this */ public function setHttpClient(\Guzzle\Http\Client $client) @@ -132,8 +126,7 @@ class Client /** * Use the given database * - * @param string $name - * + * @param string $name * @return Database */ public function selectDB($name) @@ -144,21 +137,19 @@ class Client /** * Query influxDB * - * @param string $database - * @param string $query - * @param array $params - * + * @param string $database + * @param string $query + * @param array $params * @return ResultSet * @throws Exception */ public function query($database, $query, $params = array()) { - if ($database) { $params['db'] = $database; } - $params = '?'.http_build_query(array_merge(array('q' => $query), $params)); + $params = '?' . http_build_query(array_merge(array('q' => $query), $params)); $options = array_merge($this->options, array('exceptions' => false, 'timeout' => $this->getTimeout())); @@ -168,7 +159,6 @@ class Client $raw = (string) $response->send()->getBody(); return new ResultSet($raw); - } catch (\Exception $e) { throw new Exception(sprintf('Query has failed, exception: %s', $e->getMessage())); } @@ -177,28 +167,27 @@ class Client /** * Write points to the database * - * @param string $database - * @param string $data - * @param string $precision The timestamp precision - * + * @param string $database + * @param string $data + * @param string $precision The timestamp precision * @return bool + * @throws Exception * * @internal Internal method, do not use directly - * @throws Exception */ public function write($database, $data, $precision) { try { - - $result = $this->httpClient->post($this->getBaseURI() - . '/write?db=' . $database - . '&precision=' . $precision - , null, $data, + $result = $this->httpClient->post( + $this->getBaseURI() . + '/write?db=' . $database . + '&precision=' . $precision, + null, + $data, array('timeout' => $this->getTimeout()) )->send(); - return $result->getStatusCode() == 204; - + return $result->getStatusCode() === 204; } catch (\Exception $e) { throw new Exception(sprintf('Writing has failed, exception: %s', $e->getMessage())); } @@ -218,7 +207,6 @@ class Client * List all the users * * @return array - * * @throws Exception */ public function listUsers() @@ -230,37 +218,33 @@ class Client /** * Build the client from a dsn - * * Example: https+influxdb://username:pass@localhost:8086/databasename', timeout=5 * - * @param string $dsn - * - * @param int $timeout - * @param bool $verifySSL - * + * @param string $dsn + * @param int $timeout + * @param bool $verifySSL * @return Client|Database - * * @throws ClientException */ public static function fromDSN($dsn, $timeout = 0, $verifySSL = false) { $connParams = parse_url($dsn); $schemeInfo = explode('+', $connParams['scheme']); - $dbName = null; - $modifier = null; - $scheme = $schemeInfo[0]; + $dbName = null; + $modifier = null; + $scheme = $schemeInfo[0]; if (isset($schemeInfo[1])) { $modifier = $schemeInfo[0]; - $scheme = $schemeInfo[1]; + $scheme = $schemeInfo[1]; } if ($scheme != 'influxdb') { throw new ClientException(sprintf('%s is not a valid scheme', $scheme)); } - $ssl = ($modifier && $modifier == 'https' ? true : false); - $dbName = ($connParams['path'] ? substr($connParams['path'], 1) : null); + $ssl = $modifier === 'https' ? true : false; + $dbName = $connParams['path'] ? substr($connParams['path'], 1) : null; $client = new self( $connParams['host'], @@ -274,6 +258,7 @@ class Client return ($dbName ? $client->selectDB($dbName) : $client); } + /** * @return mixed */ @@ -305,4 +290,4 @@ class Client return $names; } -} \ No newline at end of file +} diff --git a/src/InfluxDB/Client/Exception.php b/src/InfluxDB/Client/Exception.php index 1b446a2ac..0674e8686 100644 --- a/src/InfluxDB/Client/Exception.php +++ b/src/InfluxDB/Client/Exception.php @@ -9,5 +9,4 @@ namespace InfluxDB\Client; */ class Exception extends \InfluxDB\Exception { - -} \ No newline at end of file +} diff --git a/src/InfluxDB/Database.php b/src/InfluxDB/Database.php index f5d58d78a..3540aa828 100644 --- a/src/InfluxDB/Database.php +++ b/src/InfluxDB/Database.php @@ -1,13 +1,10 @@ client = $client; - - if (!$name) { + if (empty($name)) { throw new \InvalidArgumentException('No database name provided'); } - $this->name = $name; - + $this->name = $name; + $this->client = $client; } /** - * @return string db name + * @return string */ public function getName() { @@ -73,11 +65,9 @@ class Database /** * Query influxDB * - * @param string $query - * @param array $params - * + * @param string $query + * @param array $params * @return ResultSet - * * @throws Exception */ public function query($query, $params = array()) @@ -88,10 +78,8 @@ class Database /** * Create this database * - * @param RetentionPolicy $retentionPolicy - * + * @param RetentionPolicy $retentionPolicy * @return ResultSet - * * @throws DatabaseException * @throws Exception */ @@ -103,7 +91,6 @@ class Database if ($retentionPolicy) { $this->createRetentionPolicy($retentionPolicy); } - } catch (\Exception $e) { throw new DatabaseException( sprintf('Failed to created database %s, exception: %s', $this->name, $e->getMessage()) @@ -112,8 +99,7 @@ class Database } /** - * @param RetentionPolicy $retentionPolicy - * + * @param RetentionPolicy $retentionPolicy * @return ResultSet */ public function createRetentionPolicy(RetentionPolicy $retentionPolicy) @@ -124,9 +110,8 @@ class Database /** * Writes points into InfluxDB * - * @param Point[] $points Array of points - * @param string $precision The timestamp precision (defaults to nanoseconds) - * + * @param Point[] $points Array of points + * @param string $precision The timestamp precision (defaults to nanoseconds) * @return bool * @throws Exception */ @@ -135,8 +120,7 @@ class Database $payload = array(); foreach ($points as $point) { - - if (!$point instanceof Point) { + if (! $point instanceof Point) { throw new \InvalidArgumentException('An array of Point[] should be passed'); } @@ -166,7 +150,6 @@ class Database /** * @return array - * * @throws Exception */ public function listRetentionPolicies() @@ -174,7 +157,6 @@ class Database return $this->query(sprintf('SHOW RETENTION POLICIES %s', $this->name))->getPoints(); } - /** * Drop this database */ @@ -202,9 +184,8 @@ class Database } /** - * @param $method - * @param RetentionPolicy $retentionPolicy - * + * @param string $method + * @param RetentionPolicy $retentionPolicy * @return string */ protected function getRetentionPolicyQuery($method, RetentionPolicy $retentionPolicy) @@ -229,5 +210,4 @@ class Database return $query; } - -} \ No newline at end of file +} diff --git a/src/InfluxDB/Database/Exception.php b/src/InfluxDB/Database/Exception.php index fa17ab7aa..f5142b49e 100644 --- a/src/InfluxDB/Database/Exception.php +++ b/src/InfluxDB/Database/Exception.php @@ -1,12 +1,10 @@ name = $name; - $this->duration = $duration; + $this->name = $name; + $this->duration = $duration; $this->replication = $replication; - - $this->default = (bool) $default; + $this->default = (bool) $default; } -} \ No newline at end of file +} diff --git a/src/InfluxDB/Exception.php b/src/InfluxDB/Exception.php index fbf6cb5cb..868dd74c4 100644 --- a/src/InfluxDB/Exception.php +++ b/src/InfluxDB/Exception.php @@ -1,12 +1,10 @@ measurement = (string) $measurement; - $this->tags = $tags; - $this->fields = $additionalFields; + $this->tags = $tags; + $this->fields = $additionalFields; $this->fields += array('value' => (float) $value); @@ -72,7 +81,7 @@ class Point $string .= ',' . $this->arrayToString($this->tags); } - $string .= ' ' .$this->arrayToString($this->fields); + $string .= ' ' . $this->arrayToString($this->fields); if ($this->timestamp) { $string .= ' '.$this->timestamp; @@ -81,26 +90,39 @@ class Point return $string; } + /** + * @param array $arr + * @return string + */ private function arrayToString(array $arr) { $strParts = array(); foreach ($arr as $key => $value) { - $strParts[] = "{$key}={$value}"; + $strParts[] = sprintf('%s=%s', $key, $value); } - return implode(",", $strParts); + return implode(',', $strParts); } /** - * @param $timestamp - * + * @param int $timestamp * @return bool */ private function isValidTimeStamp($timestamp) { - return ((int) $timestamp === $timestamp) - && ($timestamp <= PHP_INT_MAX) - && ($timestamp >= ~PHP_INT_MAX); + if ((int) $timestamp === $timestamp) { + return true; + } + + if ($timestamp <= PHP_INT_MAX) { + return true; + } + + if ($timestamp >= ~PHP_INT_MAX) { + return true; + } + + return false; } -} \ No newline at end of file +} diff --git a/src/InfluxDB/Query/Builder.php b/src/InfluxDB/Query/Builder.php index 1709025f5..c3cad07e2 100644 --- a/src/InfluxDB/Query/Builder.php +++ b/src/InfluxDB/Query/Builder.php @@ -1,7 +1,4 @@ - */ namespace InfluxDB\Query; @@ -24,16 +21,43 @@ use InfluxDB\ResultSet; * @todo add merge * * @package InfluxDB\Query + * @author Stephen "TheCodeAssassin" Hoogendijk */ class Builder { + /** + * @var Database + */ + protected $db; - protected $db = null; + /** + * @var string + */ protected $selection = '*'; + + /** + * @var string[] + */ protected $where = array(); - protected $startTime = null; - protected $endTime = null; - protected $metric = null; + + /** + * @var string + */ + protected $startTime; + + /** + * @var string + */ + protected $endTime; + + /** + * @var string + */ + protected $metric; + + /** + * @var string + */ protected $limitClause = ''; /** @@ -45,8 +69,7 @@ class Builder } /** - * @param string $metric The metric to select (required) - * + * @param string $metric The metric to select (required) * @return $this */ public function from($metric) @@ -63,8 +86,7 @@ class Builder * * $series->select('sum(value)', * - * @param string $customSelect - * + * @param string $customSelect * @return $this */ public function select($customSelect) @@ -83,7 +105,6 @@ class Builder */ public function where(array $conditions) { - foreach ($conditions as $condition) { $this->where[] = $condition; } @@ -92,8 +113,7 @@ class Builder } /** - * @param string $field - * + * @param string $field * @return $this */ public function count($field = 'type') @@ -104,8 +124,7 @@ class Builder } /** - * @param string $field - * + * @param string $field * @return $this */ public function median($field = 'type') @@ -116,8 +135,7 @@ class Builder } /** - * @param string $field - * + * @param string $field * @return $this */ public function mean($field = 'type') @@ -128,8 +146,7 @@ class Builder } /** - * @param string $field - * + * @param string $field * @return $this */ public function sum($field = 'type') @@ -140,8 +157,7 @@ class Builder } /** - * @param string $field - * + * @param string $field * @return $this */ public function first($field = 'type') @@ -152,8 +168,7 @@ class Builder } /** - * @param string $field - * + * @param string $field * @return $this */ public function last($field = 'type') @@ -166,9 +181,8 @@ class Builder /** * Set's the time range to select data from * - * @param int $from Unix timestamp from - * @param int $to Unix timestamp to - * + * @param int $from + * @param int $to * @return $this */ public function setTimeRange($from, $to) @@ -207,7 +221,6 @@ class Builder return $this; } - /** * @return string */ @@ -233,12 +246,13 @@ class Builder { $query = sprintf("SELECT %s FROM %s", $this->selection, $this->metric); - if (!$this->metric) { + if (! $this->metric) { throw new \InvalidArgumentException('No metric provided to from()'); } - for ($i=0; $i < count($this->where); $i++) { + for ($i = 0; $i < count($this->where); $i++) { $selection = 'WHERE'; + if ($i > 0) { $selection = 'AND'; } @@ -254,4 +268,4 @@ class Builder return $query; } -} \ No newline at end of file +} diff --git a/src/InfluxDB/Query/Exception.php b/src/InfluxDB/Query/Exception.php index 4571efb74..448a41e97 100644 --- a/src/InfluxDB/Query/Exception.php +++ b/src/InfluxDB/Query/Exception.php @@ -1,12 +1,10 @@ raw = $raw; - - $this->parsedResults = json_decode($raw, true); + $this->parsedResults = json_decode((string) $raw, true); if (json_last_error() !== JSON_ERROR_NONE) { - throw new \InvalidArgumentException("Invalid JSON"); + throw new \InvalidArgumentException('Invalid JSON'); } // There was an error in the query thrown by influxdb if (isset($this->parsedResults['error'])) { throw new ClientException($this->parsedResults['error']); + } - // Check if there are errors in the first serie - } elseif (isset($this->parsedResults['results'][0]['error'])) { + // Check if there are errors in the first serie + if (isset($this->parsedResults['results'][0]['error'])) { throw new ClientException($this->parsedResults['results'][0]['error']); } } /** - * @param $metricName - * @param array $tags - * + * @param $metricName + * @param array $tags * @return array $points */ public function getPoints($metricName = '', array $tags = array()) @@ -62,7 +52,6 @@ class ResultSet $series = $this->getSeries(); foreach ($series as $serie) { - if ((empty($metricName) && empty($tags) || $serie['name'] == $metricName || (isset($serie['tags']) && array_intersect($tags, $serie['tags']))) @@ -82,30 +71,26 @@ class ResultSet * each containing the keys for a series * * @throws Exception - * * @return array $series */ public function getSeries() { - $pickSeries = function ($object) { - - if (isset($object['error'])) { - throw new ClientException($object['error']); - } - - return (isset($object['series']) ? $object['series'] : array()); - }; - - // we use array_shift because of compatibility with php5.3 - // Foreach object, pick series key - $map = array_map($pickSeries, $this->parsedResults['results']); return array_shift( - $map + array_map( + function ($object) { + if (isset($object['error'])) { + throw new ClientException($object['error']); + } + + return isset($object['series']) ? $object['series'] : array(); + }, + $this->parsedResults['results'] + ) ); } /** - * @param array $serie + * @param array $serie * @return array */ private function getPointsFromSerie(array $serie) @@ -113,13 +98,9 @@ class ResultSet $points = array(); foreach ($serie['values'] as $point) { - $points[] = array_combine( - $serie['columns'], - $point - ); + $points[] = array_combine($serie['columns'], $point); } return $points; } - -} \ No newline at end of file +} From 5bc2b9fabd018a4b0243021e1666f2fffe032280 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 20 Jul 2015 09:54:00 -0300 Subject: [PATCH 54/72] Use native type-checking --- src/InfluxDB/Database.php | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/InfluxDB/Database.php b/src/InfluxDB/Database.php index 3540aa828..713fa2753 100644 --- a/src/InfluxDB/Database.php +++ b/src/InfluxDB/Database.php @@ -117,15 +117,12 @@ class Database */ public function writePoints(array $points, $precision = self::PRECISION_NANOSECONDS) { - $payload = array(); - - foreach ($points as $point) { - if (! $point instanceof Point) { - throw new \InvalidArgumentException('An array of Point[] should be passed'); - } - - $payload[] = (string) $point; - } + $payload = array_map( + function (Point $point) { + return (string) $point; + }, + $points + ); return $this->client->write($this->name, implode(PHP_EOL, $payload), $precision); } @@ -190,7 +187,6 @@ class Database */ protected function getRetentionPolicyQuery($method, RetentionPolicy $retentionPolicy) { - if (!in_array($method, array('CREATE', 'ALTER'))) { throw new \InvalidArgumentException(sprintf('%s is not a valid method')); } From 6419531178514b578b0855ac80e0ffba0c7031c5 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 20 Jul 2015 09:56:10 -0300 Subject: [PATCH 55/72] Use array_merge instead --- src/InfluxDB/Point.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/InfluxDB/Point.php b/src/InfluxDB/Point.php index c32eda88d..03336eb79 100644 --- a/src/InfluxDB/Point.php +++ b/src/InfluxDB/Point.php @@ -55,9 +55,7 @@ class Point $this->measurement = (string) $measurement; $this->tags = $tags; - $this->fields = $additionalFields; - - $this->fields += array('value' => (float) $value); + $this->fields = array_merge($additionalFields, array('value' => (float) $value)); if ($timestamp && !$this->isValidTimeStamp($timestamp)) { throw new DatabaseException(sprintf('%s is not a valid timestamp', $timestamp)); From dfe45c0ff206ad2ba98b619187fd7db4f47d092a Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 20 Jul 2015 09:57:10 -0300 Subject: [PATCH 56/72] Cast all to (int) --- src/InfluxDB/Database/RetentionPolicy.php | 4 ++-- src/InfluxDB/Query/Builder.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/InfluxDB/Database/RetentionPolicy.php b/src/InfluxDB/Database/RetentionPolicy.php index fc4773cca..cbb8ae6b2 100644 --- a/src/InfluxDB/Database/RetentionPolicy.php +++ b/src/InfluxDB/Database/RetentionPolicy.php @@ -40,9 +40,9 @@ class RetentionPolicy */ public function __construct($name, $duration = '1d', $replication = 1, $default = false) { - $this->name = $name; + $this->name = (string) $name; $this->duration = $duration; - $this->replication = $replication; + $this->replication = (int) $replication; $this->default = (bool) $default; } } diff --git a/src/InfluxDB/Query/Builder.php b/src/InfluxDB/Query/Builder.php index c3cad07e2..1060bc39d 100644 --- a/src/InfluxDB/Query/Builder.php +++ b/src/InfluxDB/Query/Builder.php @@ -187,8 +187,8 @@ class Builder */ public function setTimeRange($from, $to) { - $fromDate = date('Y-m-d H:i:s', $from); - $toDate = date('Y-m-d H:i:s', $to); + $fromDate = date('Y-m-d H:i:s', (int) $from); + $toDate = date('Y-m-d H:i:s', (int) $to); $this->where(array("time > '$fromDate'", "time < '$toDate'")); From 5536533d652f449fa75ebd7def3382f1b993967f Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 20 Jul 2015 10:03:21 -0300 Subject: [PATCH 57/72] Fix composer.json indentation --- composer.json | 91 ++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/composer.json b/composer.json index eae2c469e..a21d4e43d 100644 --- a/composer.json +++ b/composer.json @@ -1,53 +1,46 @@ { - "name": "influxdb/influxdb-php", - "description": "InfluxDB client library for PHP", - "keywords": [ - "influxdb", - "client", - "time series", - "influxdb client", - "influxdb class", - "influxdb library" - ], - "minimum-stability": "dev", - "authors": [ - { - "name": "Stephen Hoogendijk", - "email": "stephen@tca0.nl" - }, - { - "name": "Daniel Martinez", - "email": "danimartcas@hotmail.com" - } - ], - "require": { - "php": ">=5.3", - "guzzlehttp/guzzle": "3.*", - "symfony/event-dispatcher": "2.*" - - }, - "require-dev": { - "codeclimate/php-test-reporter": "0.*", - "symfony/config": "~2.8", - "symfony/console": "~2.8", - "symfony/filesystem": "~2.8", - "symfony/stopwatch": "~2.8", - "symfony/yaml": "~2.8" - }, - "scripts": { - "post-install-cmd": [ + "name": "influxdb/influxdb-php", + "description": "InfluxDB client library for PHP", + "keywords": [ + "influxdb", + "client", + "time series", + "influxdb client", + "influxdb class", + "influxdb library" ], - "post-update-cmd": [ - ] - }, - "autoload": { - "psr-4": { - "InfluxDB\\": "src/InfluxDB" + "minimum-stability": "dev", + "authors": [ + { + "name": "Stephen Hoogendijk", + "email": "stephen@tca0.nl" + }, + { + "name": "Daniel Martinez", + "email": "danimartcas@hotmail.com" + } + ], + "require": { + "php": ">=5.3", + "guzzlehttp/guzzle": "3.*", + "symfony/event-dispatcher": "2.*" + }, + "require-dev": { + "codeclimate/php-test-reporter": "0.*", + "symfony/config": "~2.8", + "symfony/console": "~2.8", + "symfony/filesystem": "~2.8", + "symfony/stopwatch": "~2.8", + "symfony/yaml": "~2.8" + }, + "autoload": { + "psr-4": { + "InfluxDB\\": "src/InfluxDB" + } + }, + "autoload-dev": { + "psr-4": { + "InfluxDB\\Test\\": "tests" + } } - }, - "autoload-dev": { - "psr-4": { - "InfluxDB\\Test\\": "tests" - } - } } From fe5c97873fe3edd85a7f5ad7ab8b57c6ab5c57c9 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 20 Jul 2015 10:03:41 -0300 Subject: [PATCH 58/72] `composer validate` complains about `license` entry --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index a21d4e43d..d6f44f717 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,7 @@ { "name": "influxdb/influxdb-php", "description": "InfluxDB client library for PHP", + "license": "MIT", "keywords": [ "influxdb", "client", From d266b25a5ab9187509c30ab875e913ab33bc999a Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 20 Jul 2015 10:10:46 -0300 Subject: [PATCH 59/72] Fix `Only variables should be passed by reference` --- src/InfluxDB/ResultSet.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/InfluxDB/ResultSet.php b/src/InfluxDB/ResultSet.php index ccecf60ca..7c8e0c5bc 100644 --- a/src/InfluxDB/ResultSet.php +++ b/src/InfluxDB/ResultSet.php @@ -75,18 +75,18 @@ class ResultSet */ public function getSeries() { - return array_shift( - array_map( - function ($object) { - if (isset($object['error'])) { - throw new ClientException($object['error']); - } + $series = array_map( + function ($object) { + if (isset($object['error'])) { + throw new ClientException($object['error']); + } - return isset($object['series']) ? $object['series'] : array(); - }, - $this->parsedResults['results'] - ) + return isset($object['series']) ? $object['series'] : array(); + }, + $this->parsedResults['results'] ); + + return array_shift($series); } /** From 0a11cfd315827d98b968eb7cd7a75d38450be477 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 20 Jul 2015 10:28:59 -0300 Subject: [PATCH 60/72] Always ensure `value` --- src/InfluxDB/Point.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/InfluxDB/Point.php b/src/InfluxDB/Point.php index 03336eb79..12cd119c4 100644 --- a/src/InfluxDB/Point.php +++ b/src/InfluxDB/Point.php @@ -54,8 +54,10 @@ class Point } $this->measurement = (string) $measurement; - $this->tags = $tags; - $this->fields = array_merge($additionalFields, array('value' => (float) $value)); + $this->tags = $tags; + $this->fields = $additionalFields; + + $this->fields['value'] = (float) $value; if ($timestamp && !$this->isValidTimeStamp($timestamp)) { throw new DatabaseException(sprintf('%s is not a valid timestamp', $timestamp)); @@ -113,11 +115,7 @@ class Point return true; } - if ($timestamp <= PHP_INT_MAX) { - return true; - } - - if ($timestamp >= ~PHP_INT_MAX) { + if ($timestamp <= PHP_INT_MAX && $timestamp >= ~PHP_INT_MAX) { return true; } From 2584146a44d7c82dd6225779a64779ee995c1f32 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 20 Jul 2015 10:31:41 -0300 Subject: [PATCH 61/72] Do not align assignments --- src/InfluxDB/Client.php | 24 +++++++++++------------ src/InfluxDB/Database.php | 2 +- src/InfluxDB/Database/RetentionPolicy.php | 6 +++--- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index bc87b5bdb..0f76df243 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -92,11 +92,11 @@ class Client $verifySSL = true, $timeout = 0 ) { - $this->host = (string) $host; - $this->port = (int) $port; - $this->username = (string) $username; - $this->password = (string) $password; - $this->timeout = (int) $timeout; + $this->host = (string) $host; + $this->port = (int) $port; + $this->username = (string) $username; + $this->password = (string) $password; + $this->timeout = (int) $timeout; $this->verifySSL = (bool) $verifySSL; if ($ssl) { @@ -107,7 +107,6 @@ class Client // the the base URI $this->baseURI = sprintf('%s://%s:%d', $this->scheme, $this->host, $this->port); $this->httpClient = new \Guzzle\Http\Client($this->getBaseURI()); - } /** @@ -230,20 +229,20 @@ class Client { $connParams = parse_url($dsn); $schemeInfo = explode('+', $connParams['scheme']); - $dbName = null; - $modifier = null; - $scheme = $schemeInfo[0]; + $dbName = null; + $modifier = null; + $scheme = $schemeInfo[0]; if (isset($schemeInfo[1])) { $modifier = $schemeInfo[0]; - $scheme = $schemeInfo[1]; + $scheme = $schemeInfo[1]; } if ($scheme != 'influxdb') { throw new ClientException(sprintf('%s is not a valid scheme', $scheme)); } - $ssl = $modifier === 'https' ? true : false; + $ssl = $modifier === 'https' ? true : false; $dbName = $connParams['path'] ? substr($connParams['path'], 1) : null; $client = new self( @@ -276,8 +275,7 @@ class Client } /** - * @param array $points - * + * @param array $points * @return array */ protected function pointsToArray(array $points) diff --git a/src/InfluxDB/Database.php b/src/InfluxDB/Database.php index 713fa2753..922155672 100644 --- a/src/InfluxDB/Database.php +++ b/src/InfluxDB/Database.php @@ -50,7 +50,7 @@ class Database throw new \InvalidArgumentException('No database name provided'); } - $this->name = $name; + $this->name = (string) $name; $this->client = $client; } diff --git a/src/InfluxDB/Database/RetentionPolicy.php b/src/InfluxDB/Database/RetentionPolicy.php index cbb8ae6b2..c795f4647 100644 --- a/src/InfluxDB/Database/RetentionPolicy.php +++ b/src/InfluxDB/Database/RetentionPolicy.php @@ -40,9 +40,9 @@ class RetentionPolicy */ public function __construct($name, $duration = '1d', $replication = 1, $default = false) { - $this->name = (string) $name; - $this->duration = $duration; + $this->name = (string) $name; + $this->duration = $duration; $this->replication = (int) $replication; - $this->default = (bool) $default; + $this->default = (bool) $default; } } From 1de116fd0352f40dd158071cd9a5a8ab44aceabd Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Tue, 21 Jul 2015 00:00:00 +0200 Subject: [PATCH 62/72] Rewrite to allow for pluggable adapters, removed support for PHP < 5.5, Added UDP support --- CONTRIBUTE.md | 17 +- README.md | 32 ++- composer.json | 4 +- composer.lock | 270 ++++++++++++++----- src/InfluxDB/Client.php | 117 ++++---- src/InfluxDB/Database.php | 21 +- src/InfluxDB/Driver/DriverInterface.php | 50 ++++ src/InfluxDB/Driver/Exception.php | 16 ++ src/InfluxDB/Driver/Guzzle.php | 113 ++++++++ src/InfluxDB/Driver/QueryDriverInterface.php | 22 ++ src/InfluxDB/Driver/UDP.php | 92 +++++++ src/InfluxDB/Point.php | 6 +- src/InfluxDB/ResultSet.php | 8 +- tests/unit/DatabaseTest.php | 1 - 14 files changed, 627 insertions(+), 142 deletions(-) create mode 100644 src/InfluxDB/Driver/DriverInterface.php create mode 100644 src/InfluxDB/Driver/Exception.php create mode 100644 src/InfluxDB/Driver/Guzzle.php create mode 100644 src/InfluxDB/Driver/QueryDriverInterface.php create mode 100644 src/InfluxDB/Driver/UDP.php diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md index a71780b0d..d9348f142 100644 --- a/CONTRIBUTE.md +++ b/CONTRIBUTE.md @@ -8,8 +8,8 @@ Here are a few ways you can help make this project better. ## Team members -Stephen "TheCodeAssassin" Hoogendijk -Daniel "danibrutal" Martinez +* Stephen "TheCodeAssassin" Hoogendijk +* Daniel "danibrutal" Martinez ## Helping out @@ -29,9 +29,22 @@ In order for your pull requests to get accepted we hold all the code to the foll * Do not use left hand conditions such as false == $something * New features need to be documented * Breaking changes should be well highlighted and explained in the PR +* Only short-array syntax should be used for arrays +* Use regular string concatenation for single-variable strings, and sprintf for multi-variable strings +* Do not align variable assignments The following is optional but encouraged: * Code should be documented * Code should be unit tested * Do not write conditions like false === $something, rather $something === false. + +## Special thanks + +We would like to thank the following people for helping to make this library possible: + +* InfluxDB Community +* LeaseWeb Technologies +* Paul Dix +* Sean Beckett +* CentaurWarchief \ No newline at end of file diff --git a/README.md b/README.md index d8c0ea9b0..2f57b9eef 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ Writing data is done by providing an array of points to the writePoints method o ); // we are writing unix timestamps, which have a second precision - $newPoints = $database->writePoints($points, Database::PRECISION_SECONDS); + $result = $database->writePoints($points, Database::PRECISION_SECONDS); ``` @@ -115,6 +115,27 @@ measurements to InfluxDB. The point class allows one to easily write data in bat The name of a measurement and the value are mandatory. Additional fields, tags and a timestamp are optional. InfluxDB takes the current time as the default timestamp. +#### Writing data using udp + +First, set your InfluxDB host to support incoming UDP sockets: + +```ini +[udp] + enabled = true + bind-address = ":4444" + database = "test_db" +``` + +Then, configure the UDP driver in the client: + +```php + // set the udp driver + $client->setDriver(new \InfluxDB\Driver\UDP($client->getHost(), 4444)); + + // now just write your points like you normally would + $result = $database->writePoints($points, Database::PRECISION_SECONDS); +``` + #### Timestamp precision It's important to provide the correct precision when adding a timestamp to a Point object. This is because @@ -147,7 +168,14 @@ This library makes it easy to provide a retention policy when creating a databas $database = $client->selectDB('influx_test_db'); // create the database with a retention policy - $result = $database->create(new RetentionPolicy('test', '5d', 1, true)); + $result = $database->create(new RetentionPolicy('test', '5d', 1, true)); + + // check if a database exists then create it if it doesn't + $database = $client->selectDB('test_db'); + + if (!$database->exists()) { + $database->create(new RetentionPolicy('test', '1d', 2, true)); + } ``` diff --git a/composer.json b/composer.json index d6f44f717..7af0fafe8 100644 --- a/composer.json +++ b/composer.json @@ -22,8 +22,8 @@ } ], "require": { - "php": ">=5.3", - "guzzlehttp/guzzle": "3.*", + "php": ">=5.5", + "guzzlehttp/guzzle": "6.*", "symfony/event-dispatcher": "2.*" }, "require-dev": { diff --git a/composer.lock b/composer.lock index e26469b28..a2fb5ba28 100644 --- a/composer.lock +++ b/composer.lock @@ -1,73 +1,47 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "3db2b5749b72a686e2a905c11e313ae4", + "hash": "ee3f2e2a4eb50f8de36c6efbff37fe71", "packages": [ { "name": "guzzlehttp/guzzle", - "version": "v3.8.1", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba" + "reference": "1879fbe853b0c64d109e369c7aeff09849e62d1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/4de0618a01b34aa1c8c33a3f13f396dcd3882eba", - "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/1879fbe853b0c64d109e369c7aeff09849e62d1e", + "reference": "1879fbe853b0c64d109e369c7aeff09849e62d1e", "shasum": "" }, "require": { - "ext-curl": "*", - "php": ">=5.3.3", - "symfony/event-dispatcher": ">=2.1" - }, - "replace": { - "guzzle/batch": "self.version", - "guzzle/cache": "self.version", - "guzzle/common": "self.version", - "guzzle/http": "self.version", - "guzzle/inflection": "self.version", - "guzzle/iterator": "self.version", - "guzzle/log": "self.version", - "guzzle/parser": "self.version", - "guzzle/plugin": "self.version", - "guzzle/plugin-async": "self.version", - "guzzle/plugin-backoff": "self.version", - "guzzle/plugin-cache": "self.version", - "guzzle/plugin-cookie": "self.version", - "guzzle/plugin-curlauth": "self.version", - "guzzle/plugin-error-response": "self.version", - "guzzle/plugin-history": "self.version", - "guzzle/plugin-log": "self.version", - "guzzle/plugin-md5": "self.version", - "guzzle/plugin-mock": "self.version", - "guzzle/plugin-oauth": "self.version", - "guzzle/service": "self.version", - "guzzle/stream": "self.version" + "guzzlehttp/promises": "~1.0", + "guzzlehttp/psr7": "~1.1", + "php": ">=5.5.0" }, "require-dev": { - "doctrine/cache": "*", - "monolog/monolog": "1.*", - "phpunit/phpunit": "3.7.*", - "psr/log": "1.0.*", - "symfony/class-loader": "*", - "zendframework/zend-cache": "<2.3", - "zendframework/zend-log": "<2.3" + "ext-curl": "*", + "phpunit/phpunit": "~4.0", + "psr/log": "~1.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.8-dev" + "dev-master": "6.0-dev" } }, "autoload": { - "psr-0": { - "Guzzle": "src/", - "Guzzle\\Tests": "tests/" + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -79,13 +53,9 @@ "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" - }, - { - "name": "Guzzle Community", - "homepage": "https://github.com/guzzle/guzzle/contributors" } ], - "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", + "description": "Guzzle is a PHP HTTP client library", "homepage": "http://guzzlephp.org/", "keywords": [ "client", @@ -96,7 +66,165 @@ "rest", "web service" ], - "time": "2014-01-28 22:29:15" + "time": "2015-07-10 20:04:21" + }, + { + "name": "guzzlehttp/promises", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "f596be052ef429a16b2f640812fcf84392dd38f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/f596be052ef429a16b2f640812fcf84392dd38f7", + "reference": "f596be052ef429a16b2f640812fcf84392dd38f7", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2015-06-30 16:39:54" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "af0e1758de355eb113917ad79c3c0e3604bce4bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/af0e1758de355eb113917ad79c3c0e3604bce4bd", + "reference": "af0e1758de355eb113917ad79c3c0e3604bce4bd", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "PSR-7 message implementation", + "keywords": [ + "http", + "message", + "stream", + "uri" + ], + "time": "2015-06-24 19:55:15" + }, + { + "name": "psr/http-message", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2015-05-04 20:22:00" }, { "name": "symfony/event-dispatcher", @@ -423,12 +551,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/Config.git", - "reference": "cceb1141805d401e6f7d2e0b1365bf6a15917778" + "reference": "358ec929e494b6f12d8508d88357cbd7383a10ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Config/zipball/cceb1141805d401e6f7d2e0b1365bf6a15917778", - "reference": "cceb1141805d401e6f7d2e0b1365bf6a15917778", + "url": "https://api.github.com/repos/symfony/Config/zipball/358ec929e494b6f12d8508d88357cbd7383a10ca", + "reference": "358ec929e494b6f12d8508d88357cbd7383a10ca", "shasum": "" }, "require": { @@ -465,7 +593,7 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2015-06-28 18:28:18" + "time": "2015-07-09 16:11:14" }, { "name": "symfony/console", @@ -473,12 +601,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/Console.git", - "reference": "2a909e48c528c7c9b22caff6ff622c6c69032bfc" + "reference": "fd85e7517e79a2bceafcee8f7e8b7bbd0919a90a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/2a909e48c528c7c9b22caff6ff622c6c69032bfc", - "reference": "2a909e48c528c7c9b22caff6ff622c6c69032bfc", + "url": "https://api.github.com/repos/symfony/Console/zipball/fd85e7517e79a2bceafcee8f7e8b7bbd0919a90a", + "reference": "fd85e7517e79a2bceafcee8f7e8b7bbd0919a90a", "shasum": "" }, "require": { @@ -522,7 +650,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2015-06-22 16:34:55" + "time": "2015-07-16 12:22:14" }, { "name": "symfony/filesystem", @@ -530,12 +658,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/Filesystem.git", - "reference": "5db575c1ad5f62363c098114cf482bbd5d15349a" + "reference": "9f70c5625a32b2f1e6fc37222f52b4e0eb437b0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Filesystem/zipball/5db575c1ad5f62363c098114cf482bbd5d15349a", - "reference": "5db575c1ad5f62363c098114cf482bbd5d15349a", + "url": "https://api.github.com/repos/symfony/Filesystem/zipball/9f70c5625a32b2f1e6fc37222f52b4e0eb437b0e", + "reference": "9f70c5625a32b2f1e6fc37222f52b4e0eb437b0e", "shasum": "" }, "require": { @@ -571,7 +699,7 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2015-06-18 16:14:27" + "time": "2015-07-09 16:11:14" }, { "name": "symfony/stopwatch", @@ -579,12 +707,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/Stopwatch.git", - "reference": "a3cf998e50cae3e32e81e401150c7d4b3ecc03d5" + "reference": "cd5f0dc1d3d0e2c83461dad77e20a9186beb6146" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/a3cf998e50cae3e32e81e401150c7d4b3ecc03d5", - "reference": "a3cf998e50cae3e32e81e401150c7d4b3ecc03d5", + "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/cd5f0dc1d3d0e2c83461dad77e20a9186beb6146", + "reference": "cd5f0dc1d3d0e2c83461dad77e20a9186beb6146", "shasum": "" }, "require": { @@ -620,7 +748,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2015-06-04 20:21:09" + "time": "2015-07-01 18:24:26" }, { "name": "symfony/yaml", @@ -628,12 +756,12 @@ "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "f248a72777f3fec2bcafdce3ccd94086250448e1" + "reference": "000e7fc2653335cd42c6d21405dac1c74224a387" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/f248a72777f3fec2bcafdce3ccd94086250448e1", - "reference": "f248a72777f3fec2bcafdce3ccd94086250448e1", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/000e7fc2653335cd42c6d21405dac1c74224a387", + "reference": "000e7fc2653335cd42c6d21405dac1c74224a387", "shasum": "" }, "require": { @@ -669,7 +797,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2015-06-19 15:09:14" + "time": "2015-07-01 14:16:54" } ], "aliases": [], @@ -678,7 +806,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.3" + "php": ">=5.5" }, "platform-dev": [] } diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index 0f76df243..8a49d3ecc 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -3,6 +3,9 @@ namespace InfluxDB; use InfluxDB\Client\Exception as ClientException; +use InfluxDB\Driver\DriverInterface; +use InfluxDB\Driver\Guzzle; +use InfluxDB\Driver\QueryDriverInterface; /** * Class Client @@ -72,6 +75,11 @@ class Client */ protected $options = array(); + /** + * @var DriverInterface + */ + protected $driver; + /** * @param string $host * @param int $port @@ -80,8 +88,6 @@ class Client * @param bool $ssl * @param bool $verifySSL * @param int $timeout - * - * @todo add UDP support */ public function __construct( $host, @@ -101,25 +107,18 @@ class Client if ($ssl) { $this->scheme = 'https'; - $this->options += array('verify' => $verifySSL); + $this->options['verify'] = $verifySSL; } // the the base URI $this->baseURI = sprintf('%s://%s:%d', $this->scheme, $this->host, $this->port); - $this->httpClient = new \Guzzle\Http\Client($this->getBaseURI()); - } - /** - * For testing - * - * @param \Guzzle\Http\Client $client - * @return $this - */ - public function setHttpClient(\Guzzle\Http\Client $client) - { - $this->httpClient = $client; - - return $this; + // set the default driver to guzzle + $this->driver = new Guzzle([ + 'timeout' => $this->timeout, + 'base_uri' => $this->baseURI, + 'verify' => $this->verifySSL + ]); } /** @@ -142,56 +141,34 @@ class Client * @return ResultSet * @throws Exception */ - public function query($database, $query, $params = array()) + public function query($database, $query, $params = []) { + + if (!$this->driver instanceof QueryDriverInterface) { + throw new Exception('The currently configured driver does not support query operations'); + } + if ($database) { $params['db'] = $database; } - $params = '?' . http_build_query(array_merge(array('q' => $query), $params)); - - $options = array_merge($this->options, array('exceptions' => false, 'timeout' => $this->getTimeout())); + $this->driver->setParameters([ + 'url' => 'query?' . http_build_query(array_merge(['q' => $query], $params)), + 'database' => $database, + 'method' => 'get' + ]); try { - $response = $this->httpClient->get('query'.$params, null, $options); + // send the data + $this->driver->send(); - $raw = (string) $response->send()->getBody(); + return $this->driver->getResultSet(); - return new ResultSet($raw); } catch (\Exception $e) { throw new Exception(sprintf('Query has failed, exception: %s', $e->getMessage())); } } - /** - * Write points to the database - * - * @param string $database - * @param string $data - * @param string $precision The timestamp precision - * @return bool - * @throws Exception - * - * @internal Internal method, do not use directly - */ - public function write($database, $data, $precision) - { - try { - $result = $this->httpClient->post( - $this->getBaseURI() . - '/write?db=' . $database . - '&precision=' . $precision, - null, - $data, - array('timeout' => $this->getTimeout()) - )->send(); - - return $result->getStatusCode() === 204; - } catch (\Exception $e) { - throw new Exception(sprintf('Writing has failed, exception: %s', $e->getMessage())); - } - } - /** * List all the databases */ @@ -275,12 +252,12 @@ class Client } /** - * @param array $points + * @param Point[] $points * @return array */ protected function pointsToArray(array $points) { - $names = array(); + $names = []; foreach ($points as $item) { $names[] = $item['name']; @@ -288,4 +265,36 @@ class Client return $names; } + + /** + * @param Driver\DriverInterface $driver + */ + public function setDriver(DriverInterface $driver) + { + $this->driver = $driver; + } + + /** + * @return DriverInterface + */ + public function getDriver() + { + return $this->driver; + } + + /** + * @return string + */ + public function getHost() + { + return $this->host; + } + + /** + * @return DriverInterface + */ + public function getDefaultDriver() + { + return $this->defaultDriver; + } } diff --git a/src/InfluxDB/Database.php b/src/InfluxDB/Database.php index 922155672..4cc56cf5f 100644 --- a/src/InfluxDB/Database.php +++ b/src/InfluxDB/Database.php @@ -70,7 +70,7 @@ class Database * @return ResultSet * @throws Exception */ - public function query($query, $params = array()) + public function query($query, $params = []) { return $this->client->query($this->name, $query, $params); } @@ -124,7 +124,22 @@ class Database $points ); - return $this->client->write($this->name, implode(PHP_EOL, $payload), $precision); + try { + $driver = $this->client->getDriver(); + $driver->setParameters([ + 'url' => sprintf('write?db=%s&precision=%s', $this->name, $precision), + 'database' => $this->name, + 'method' => 'post' + ]); + + // send the points to influxDB + $driver->send(implode(PHP_EOL, $payload)); + + return $driver->isSuccess(); + + } catch (\Exception $e) { + throw new Exception(sprintf('Writing has failed, exception: %s', $e->getMessage())); + } } /** @@ -187,7 +202,7 @@ class Database */ protected function getRetentionPolicyQuery($method, RetentionPolicy $retentionPolicy) { - if (!in_array($method, array('CREATE', 'ALTER'))) { + if (!in_array($method, ['CREATE', 'ALTER'])) { throw new \InvalidArgumentException(sprintf('%s is not a valid method')); } diff --git a/src/InfluxDB/Driver/DriverInterface.php b/src/InfluxDB/Driver/DriverInterface.php new file mode 100644 index 000000000..cb1eddfbd --- /dev/null +++ b/src/InfluxDB/Driver/DriverInterface.php @@ -0,0 +1,50 @@ + 'name of the database', + * 'url' => 'URL to the resource', + * 'method' => 'HTTP method used' + * ] + * + * @param array $parameters + * + * @return mixed + */ + public function setParameters(array $parameters); + + /** + * Send the data + * + * @param $data + * + * @return mixed + */ + public function send($data = null); + + /** + * Should return if sending the data was successful + * + * @return bool + */ + public function isSuccess(); + +} diff --git a/src/InfluxDB/Driver/Exception.php b/src/InfluxDB/Driver/Exception.php new file mode 100644 index 000000000..237766eee --- /dev/null +++ b/src/InfluxDB/Driver/Exception.php @@ -0,0 +1,16 @@ +httpClient = new Client([ + 'timeout' => $config['timeout'], + 'verify' => $config['verify'], + 'base_uri' => $config['base_uri'] + ]); + + $this->config = $config; + } + + /** + * Called by the client write() method, will pass an array of required parameters such as db name + * + * will contain the following parameters: + * + * [ + * 'database' => 'name of the database', + * 'url' => 'URL to the resource', + * 'method' => 'HTTP method used' + * ] + * + * @param array $parameters + * + * @return mixed + */ + public function setParameters(array $parameters) + { + $this->parameters = $parameters; + } + + /** + * Send the data + * + * @param $data + * + * @throws Exception + * @return mixed + */ + public function send($data = null) + { + $requestObject = new Request($this->parameters['method'], $this->parameters['url'], [], $data); + + $this->response = $this->httpClient->send($requestObject); + } + + /** + * Should return if sending the data was successful + * + * @return bool + */ + public function isSuccess() + { + return in_array($this->response->getStatusCode(), ['200', '204']); + } + + /** + * @return ResultSet + */ + public function getResultSet() + { + $raw = (string) $this->response->getBody(true); + + return new ResultSet($raw); + } +} diff --git a/src/InfluxDB/Driver/QueryDriverInterface.php b/src/InfluxDB/Driver/QueryDriverInterface.php new file mode 100644 index 000000000..13830e83a --- /dev/null +++ b/src/InfluxDB/Driver/QueryDriverInterface.php @@ -0,0 +1,22 @@ +config['host'] = $host; + $this->config['port'] = $port; + + // create a socket connection to check if InfluxDB is alive + $socket = fsockopen('udp://' .$host, $port); + if (!$socket) { + throw new Exception('There is no InfluxDB UDP service running on port '. $port); + } + + fclose($socket); + } + + /** + * Called by the client write() method, will pass an array of required parameters such as db name + * + * will contain the following parameters: + * + * [ + * 'database' => 'name of the database', + * 'url' => 'URL to the resource', + * 'method' => 'HTTP method used' + * ] + * + * @param array $parameters + * + * @return mixed + */ + public function setParameters(array $parameters) + { + $this->parameters = $parameters; + } + + /** + * Send the data + * + * @param $data + * + * @return mixed + */ + public function send($data = null) + { + $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); + socket_sendto($socket, $data, strlen($data), 0, $this->config['host'], $this->config['port']); + socket_close($socket); + + return true; + } + + /** + * Should return if sending the data was successful + * + * @return bool + */ + public function isSuccess() + { + return true; + } +} \ No newline at end of file diff --git a/src/InfluxDB/Point.php b/src/InfluxDB/Point.php index 12cd119c4..17c3f72e5 100644 --- a/src/InfluxDB/Point.php +++ b/src/InfluxDB/Point.php @@ -19,12 +19,12 @@ class Point /** * @var array */ - private $tags = array(); + private $tags = []; /** * @var array */ - private $fields = array(); + private $fields = []; /** * @var string @@ -96,7 +96,7 @@ class Point */ private function arrayToString(array $arr) { - $strParts = array(); + $strParts = []; foreach ($arr as $key => $value) { $strParts[] = sprintf('%s=%s', $key, $value); diff --git a/src/InfluxDB/ResultSet.php b/src/InfluxDB/ResultSet.php index 7c8e0c5bc..66330ab42 100644 --- a/src/InfluxDB/ResultSet.php +++ b/src/InfluxDB/ResultSet.php @@ -15,7 +15,7 @@ class ResultSet /** * @var array|mixed */ - protected $parsedResults = array(); + protected $parsedResults = []; /** * @param string $raw @@ -48,7 +48,7 @@ class ResultSet */ public function getPoints($metricName = '', array $tags = array()) { - $points = array(); + $points = []; $series = $this->getSeries(); foreach ($series as $serie) { @@ -81,7 +81,7 @@ class ResultSet throw new ClientException($object['error']); } - return isset($object['series']) ? $object['series'] : array(); + return isset($object['series']) ? $object['series'] : []; }, $this->parsedResults['results'] ); @@ -95,7 +95,7 @@ class ResultSet */ private function getPointsFromSerie(array $serie) { - $points = array(); + $points = []; foreach ($serie['values'] as $point) { $points[] = array_combine($serie['columns'], $point); diff --git a/tests/unit/DatabaseTest.php b/tests/unit/DatabaseTest.php index 1b16f598f..d6da46be8 100644 --- a/tests/unit/DatabaseTest.php +++ b/tests/unit/DatabaseTest.php @@ -2,7 +2,6 @@ namespace InfluxDB\Test; - use InfluxDB\Client; use InfluxDB\Database; use InfluxDB\Point; From c2bd3c4a79217b124113111321452bdf334cf9ba Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Tue, 21 Jul 2015 00:34:08 +0200 Subject: [PATCH 63/72] Fixed existing unit tests --- src/InfluxDB/Client.php | 32 ++++++++++++++--------------- src/InfluxDB/Database.php | 8 ++++---- src/InfluxDB/Driver/Guzzle.php | 20 +++--------------- tests/unit/ClientTest.php | 37 +++++++++++++++++----------------- tests/unit/DatabaseTest.php | 16 +++++++-------- 5 files changed, 48 insertions(+), 65 deletions(-) diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index 8a49d3ecc..2cb932d1c 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -114,11 +114,15 @@ class Client $this->baseURI = sprintf('%s://%s:%d', $this->scheme, $this->host, $this->port); // set the default driver to guzzle - $this->driver = new Guzzle([ - 'timeout' => $this->timeout, - 'base_uri' => $this->baseURI, - 'verify' => $this->verifySSL - ]); + $this->driver = new Guzzle( + new \GuzzleHttp\Client( + [ + 'timeout' => $this->timeout, + 'base_uri' => $this->baseURI, + 'verify' => $this->verifySSL + ] + ) + ); } /** @@ -152,7 +156,9 @@ class Client $params['db'] = $database; } - $this->driver->setParameters([ + $driver = $this->getDriver(); + + $driver->setParameters([ 'url' => 'query?' . http_build_query(array_merge(['q' => $query], $params)), 'database' => $database, 'method' => 'get' @@ -160,9 +166,9 @@ class Client try { // send the data - $this->driver->send(); + $driver->send(); - return $this->driver->getResultSet(); + return $driver->getResultSet(); } catch (\Exception $e) { throw new Exception(sprintf('Query has failed, exception: %s', $e->getMessage())); @@ -275,7 +281,7 @@ class Client } /** - * @return DriverInterface + * @return DriverInterface|QueryDriverInterface */ public function getDriver() { @@ -289,12 +295,4 @@ class Client { return $this->host; } - - /** - * @return DriverInterface - */ - public function getDefaultDriver() - { - return $this->defaultDriver; - } } diff --git a/src/InfluxDB/Database.php b/src/InfluxDB/Database.php index 4cc56cf5f..601ca8ec5 100644 --- a/src/InfluxDB/Database.php +++ b/src/InfluxDB/Database.php @@ -127,10 +127,10 @@ class Database try { $driver = $this->client->getDriver(); $driver->setParameters([ - 'url' => sprintf('write?db=%s&precision=%s', $this->name, $precision), - 'database' => $this->name, - 'method' => 'post' - ]); + 'url' => sprintf('write?db=%s&precision=%s', $this->name, $precision), + 'database' => $this->name, + 'method' => 'post' + ]); // send the points to influxDB $driver->send(implode(PHP_EOL, $payload)); diff --git a/src/InfluxDB/Driver/Guzzle.php b/src/InfluxDB/Driver/Guzzle.php index 6ce742ed9..a9b746864 100644 --- a/src/InfluxDB/Driver/Guzzle.php +++ b/src/InfluxDB/Driver/Guzzle.php @@ -20,14 +20,6 @@ class Guzzle implements DriverInterface, QueryDriverInterface */ private $parameters; - /** - * - * Configuration for this driver - * - * @var array - */ - private $config; - /** * @var Client */ @@ -41,19 +33,13 @@ class Guzzle implements DriverInterface, QueryDriverInterface /** * Set the config for this driver * - * @param array $config + * @param Client $client * * @return mixed */ - public function __construct(array $config) + public function __construct(Client $client) { - $this->httpClient = new Client([ - 'timeout' => $config['timeout'], - 'verify' => $config['verify'], - 'base_uri' => $config['base_uri'] - ]); - - $this->config = $config; + $this->httpClient = $client; } /** diff --git a/tests/unit/ClientTest.php b/tests/unit/ClientTest.php index 9240195d5..2b6e8148b 100644 --- a/tests/unit/ClientTest.php +++ b/tests/unit/ClientTest.php @@ -2,22 +2,24 @@ namespace InfluxDB\Test; +use GuzzleHttp\Client as GuzzleClient; +use GuzzleHttp\Handler\MockHandler; +use GuzzleHttp\HandlerStack; +use GuzzleHttp\Psr7\Response; use InfluxDB\Client; -use InfluxDB\ResultSet; +use InfluxDB\Driver\Guzzle; class ClientTest extends \PHPUnit_Framework_TestCase { /** @var Client $client */ protected $client = null; - + public function testBaseURl() { $client = new Client('localhost', 8086); - $this->assertEquals( - $client->getBaseURI(), 'http://localhost:8086' - ); + $this->assertEquals($client->getBaseURI(), 'http://localhost:8086'); } public function testSelectDbShouldReturnDatabaseInstance() @@ -25,25 +27,25 @@ class ClientTest extends \PHPUnit_Framework_TestCase $client = new Client('localhost', 8086); $dbName = 'test-database'; - $db = $client->selectDB($dbName); + $database = $client->selectDB($dbName); - $this->assertInstanceOf('\InfluxDB\Database', $db); + $this->assertInstanceOf('\InfluxDB\Database', $database); - $this->assertEquals($dbName, $db->getName()); + $this->assertEquals($dbName, $database->getName()); } /** */ - public function testQuery() + public function testGuzzleQuery() { $client = new Client('localhost', 8086); $query = "some-bad-query"; $bodyResponse = file_get_contents(dirname(__FILE__) . '/result.example.json'); - $httpMockClient = $this->buildHttpMockClient($bodyResponse); + $httpMockClient = self::buildHttpMockClient($bodyResponse); - $client->setHttpClient($httpMockClient); + $client->setDriver(new Guzzle($httpMockClient)); /** @var \InfluxDB\ResultSet $result */ $result = $client->query(null, $query); @@ -54,15 +56,12 @@ class ClientTest extends \PHPUnit_Framework_TestCase /** * @return \Guzzle\Http\Client */ - protected function buildHttpMockClient($body) + public static function buildHttpMockClient($body) { - $plugin = new \Guzzle\Plugin\Mock\MockPlugin(); - $response= new \Guzzle\Http\Message\Response(200); - $response->setBody($body); - $plugin->addResponse($response); - $mockedClient = new \Guzzle\Http\Client(); - $mockedClient->addSubscriber($plugin); + // Create a mock and queue two responses. + $mock = new MockHandler([new Response(200, array(), $body)]); - return $mockedClient; + $handler = HandlerStack::create($mock); + return new GuzzleClient(['handler' => $handler]); } } \ No newline at end of file diff --git a/tests/unit/DatabaseTest.php b/tests/unit/DatabaseTest.php index d6da46be8..25fcd1cf7 100644 --- a/tests/unit/DatabaseTest.php +++ b/tests/unit/DatabaseTest.php @@ -4,6 +4,7 @@ namespace InfluxDB\Test; use InfluxDB\Client; use InfluxDB\Database; +use InfluxDB\Driver\Guzzle; use InfluxDB\Point; use InfluxDB\ResultSet; use PHPUnit_Framework_MockObject_MockObject; @@ -59,6 +60,12 @@ class DatabaseTest extends PHPUnit_Framework_TestCase ->method('listDatabases') ->will($this->returnValue(array('test123', 'test'))); + $httpMockClient = new Guzzle(ClientTest::buildHttpMockClient('')); + + // make sure the client has a valid driver + $this->mockClient->expects($this->any()) + ->method('getDriver') + ->will($this->returnValue($httpMockClient)); $this->db = new Database('influx_test_db', $this->mockClient); @@ -132,13 +139,6 @@ class DatabaseTest extends PHPUnit_Framework_TestCase 0.84 ); - $payloadExpected ="$point1\n$point2"; - - $this->mockClient->expects($this->once()) - ->method('write') - ->with($this->equalTo($this->db->getName()), $this->equalTo($payloadExpected)) - ->will($this->returnValue(true)); - - $this->db->writePoints(array($point1, $point2)); + $this->assertEquals(true, $this->db->writePoints(array($point1, $point2))); } } \ No newline at end of file From a0a16d765859de83a92d79080e5d13bc465cfe24 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Tue, 21 Jul 2015 00:36:59 +0200 Subject: [PATCH 64/72] Removed 5.3 and 5.4 from travis.yml --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2fbeca661..c71c55677 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ language: php php: - - 5.3 - - 5.4 - 5.5 - 5.6 From e8423e8846d78530e8f55df675b74bfa5b5a7e7a Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Tue, 21 Jul 2015 00:40:02 +0200 Subject: [PATCH 65/72] Updated readme --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f57b9eef..e0e8acb46 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,6 @@ Some functions are too general for a database. So these are available in the cli ## Todo -* Add UDP support * Add more admin features * More unit tests * Increase documentation (wiki?) @@ -222,6 +221,11 @@ Some functions are too general for a database. So these are available in the cli ## Changelog +####1.0.0 +* Dropped support for php 5.3 and php 5.4 +* Allowing for custom drivers +* UDP support + ####0.1.2 * Added exists method to Database class * Added time precision to database class From 6c4ce752a862d151677e940bf73745a0548909e9 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Wed, 22 Jul 2015 11:51:24 +0200 Subject: [PATCH 66/72] Changed method of sending UDP data to stream, fixed driver logic, added DSN method for creating a UDP session --- README.md | 37 ++++++++++++++++---- src/InfluxDB/Client.php | 24 ++++++++----- src/InfluxDB/Database.php | 2 +- src/InfluxDB/Driver/DriverInterface.php | 2 +- src/InfluxDB/Driver/Guzzle.php | 32 ++++++++++------- src/InfluxDB/Driver/QueryDriverInterface.php | 2 +- src/InfluxDB/Driver/UDP.php | 18 +++++----- tests/unit/ClientTest.php | 2 +- 8 files changed, 78 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index e0e8acb46..a9de6b906 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ $client = new InfluxDB\Client($host, $port); This will create a new client object which you can use to read and write points to InfluxDB. -It's also possible to create a client from a DSN: +It's also possible to create a client from a DSN (Data Source Name): ```php @@ -91,14 +91,14 @@ Writing data is done by providing an array of points to the writePoints method o new Point( 'test_metric', 0.64, - array('host' => 'server01', 'region' => 'us-west'), - array('cpucount' => 10), + ['host' => 'server01', 'region' => 'us-west'], + ['cpucount' => 10], 1435255849 // Time precision has to be set to seconds! ), new Point( 'test_metric', 0.84, - array('host' => 'server01', 'region' => 'us-west'), + ['host' => 'server01', 'region' => 'us-west'], array('cpucount' => 10), 1435255850 // Time precision has to be set to seconds! ) @@ -129,13 +129,38 @@ First, set your InfluxDB host to support incoming UDP sockets: Then, configure the UDP driver in the client: ```php - // set the udp driver + + // set the UDP driver in the client $client->setDriver(new \InfluxDB\Driver\UDP($client->getHost(), 4444)); + $points = [ + new Point( + 'test_metric', + 0.84, + ['host' => 'server01', 'region' => 'us-west'], + ['cpucount' => 10], + exec('date +%s%N') // this will produce a nanosecond timestamp in Linux operating systems + ) + ]; + // now just write your points like you normally would - $result = $database->writePoints($points, Database::PRECISION_SECONDS); + $result = $database->writePoints($points); ``` +Or simply use a DSN (Data Source Name) to send metrics using UDP: + +```php + + // get a database object using a DSN (Data Source Name) + $database = \InfluxDB\Client::fromDSN('udp+influxdb://username:pass@localhost:4444/test123'); + + // write your points + $result = $database->writePoints($points); +``` + +*Note:* It is import to note that precision will be *ignored* when you use UDP. You should always use nanosecond +precision when writing data to InfluxDB using UDP. + #### Timestamp precision It's important to provide the correct precision when adding a timestamp to a Point object. This is because diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index 2cb932d1c..faec328cf 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -6,6 +6,7 @@ use InfluxDB\Client\Exception as ClientException; use InfluxDB\Driver\DriverInterface; use InfluxDB\Driver\Guzzle; use InfluxDB\Driver\QueryDriverInterface; +use InfluxDB\Driver\UDP; /** * Class Client @@ -165,10 +166,8 @@ class Client ]); try { - // send the data - $driver->send(); - - return $driver->getResultSet(); + // perform the query and return the resultset + return $driver->query(); } catch (\Exception $e) { throw new Exception(sprintf('Query has failed, exception: %s', $e->getMessage())); @@ -200,12 +199,16 @@ class Client /** * Build the client from a dsn - * Example: https+influxdb://username:pass@localhost:8086/databasename', timeout=5 + * Examples: + * + * https+influxdb://username:pass@localhost:8086/databasename + * udp+influxdb://username:pass@localhost:4444/databasename * * @param string $dsn * @param int $timeout * @param bool $verifySSL - * @return Client|Database + * +*@return Client|Database * @throws ClientException */ public static function fromDSN($dsn, $timeout = 0, $verifySSL = false) @@ -217,12 +220,12 @@ class Client $scheme = $schemeInfo[0]; if (isset($schemeInfo[1])) { - $modifier = $schemeInfo[0]; + $modifier = strtolower($schemeInfo[0]); $scheme = $schemeInfo[1]; } if ($scheme != 'influxdb') { - throw new ClientException(sprintf('%s is not a valid scheme', $scheme)); + throw new ClientException($scheme . ' is not a valid scheme'); } $ssl = $modifier === 'https' ? true : false; @@ -238,6 +241,11 @@ class Client $timeout ); + // set the UDP driver when the DSN specifies UDP + if ($modifier == 'udp') { + $client->setDriver(new UDP($connParams['host'], $connParams['port'])); + } + return ($dbName ? $client->selectDB($dbName) : $client); } diff --git a/src/InfluxDB/Database.php b/src/InfluxDB/Database.php index 601ca8ec5..e75300261 100644 --- a/src/InfluxDB/Database.php +++ b/src/InfluxDB/Database.php @@ -133,7 +133,7 @@ class Database ]); // send the points to influxDB - $driver->send(implode(PHP_EOL, $payload)); + $driver->write(implode(PHP_EOL, $payload)); return $driver->isSuccess(); diff --git a/src/InfluxDB/Driver/DriverInterface.php b/src/InfluxDB/Driver/DriverInterface.php index cb1eddfbd..5400ba051 100644 --- a/src/InfluxDB/Driver/DriverInterface.php +++ b/src/InfluxDB/Driver/DriverInterface.php @@ -38,7 +38,7 @@ interface DriverInterface * * @return mixed */ - public function send($data = null); + public function write($data = null); /** * Should return if sending the data was successful diff --git a/src/InfluxDB/Driver/Guzzle.php b/src/InfluxDB/Driver/Guzzle.php index a9b746864..d014c1f3b 100644 --- a/src/InfluxDB/Driver/Guzzle.php +++ b/src/InfluxDB/Driver/Guzzle.php @@ -10,6 +10,11 @@ use Guzzle\Http\Message\Response; use GuzzleHttp\Psr7\Request; use InfluxDB\ResultSet; +/** + * Class Guzzle + * + * @package InfluxDB\Driver + */ class Guzzle implements DriverInterface, QueryDriverInterface { @@ -70,11 +75,22 @@ class Guzzle implements DriverInterface, QueryDriverInterface * @throws Exception * @return mixed */ - public function send($data = null) + public function write($data = null) { - $requestObject = new Request($this->parameters['method'], $this->parameters['url'], [], $data); + $this->response = $this->httpClient->post($this->parameters['url'], ['body' => $data]); + } + + /** + * @return ResultSet + */ + public function query() + { + $response = $this->httpClient->get($this->parameters['url']); + + $raw = (string) $response->getBody(); + + return new ResultSet($raw); - $this->response = $this->httpClient->send($requestObject); } /** @@ -86,14 +102,4 @@ class Guzzle implements DriverInterface, QueryDriverInterface { return in_array($this->response->getStatusCode(), ['200', '204']); } - - /** - * @return ResultSet - */ - public function getResultSet() - { - $raw = (string) $this->response->getBody(true); - - return new ResultSet($raw); - } } diff --git a/src/InfluxDB/Driver/QueryDriverInterface.php b/src/InfluxDB/Driver/QueryDriverInterface.php index 13830e83a..0966cecc3 100644 --- a/src/InfluxDB/Driver/QueryDriverInterface.php +++ b/src/InfluxDB/Driver/QueryDriverInterface.php @@ -18,5 +18,5 @@ interface QueryDriverInterface /** * @return ResultSet */ - public function getResultSet(); + public function query(); } \ No newline at end of file diff --git a/src/InfluxDB/Driver/UDP.php b/src/InfluxDB/Driver/UDP.php index 1805841f9..ac2be0ebb 100644 --- a/src/InfluxDB/Driver/UDP.php +++ b/src/InfluxDB/Driver/UDP.php @@ -35,13 +35,7 @@ class UDP implements DriverInterface $this->config['host'] = $host; $this->config['port'] = $port; - // create a socket connection to check if InfluxDB is alive - $socket = fsockopen('udp://' .$host, $port); - if (!$socket) { - throw new Exception('There is no InfluxDB UDP service running on port '. $port); - } - fclose($socket); } /** @@ -71,11 +65,15 @@ class UDP implements DriverInterface * * @return mixed */ - public function send($data = null) + public function write($data = null) { - $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); - socket_sendto($socket, $data, strlen($data), 0, $this->config['host'], $this->config['port']); - socket_close($socket); + + $host = sprintf('udp://%s:%d', $this->config['host'], $this->config['port']); + + // stream the data using UDP and suppress any errors + $stream = @stream_socket_client($host); + @stream_socket_sendto($stream, $data); + @fclose($stream); return true; } diff --git a/tests/unit/ClientTest.php b/tests/unit/ClientTest.php index 2b6e8148b..095d534b0 100644 --- a/tests/unit/ClientTest.php +++ b/tests/unit/ClientTest.php @@ -54,7 +54,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase } /** - * @return \Guzzle\Http\Client + * @return GuzzleClient */ public static function buildHttpMockClient($body) { From e7c6630329141497343227e30863773a684269dd Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Wed, 22 Jul 2015 13:37:12 +0200 Subject: [PATCH 67/72] Added ability to add measurements that do not have a value --- README.md | 40 +++++++++++++++++++++++++++++++--------- src/InfluxDB/Point.php | 6 ++++-- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index a9de6b906..cadad51ea 100644 --- a/README.md +++ b/README.md @@ -89,18 +89,18 @@ Writing data is done by providing an array of points to the writePoints method o // create an array of points $points = array( new Point( - 'test_metric', - 0.64, - ['host' => 'server01', 'region' => 'us-west'], - ['cpucount' => 10], + 'test_metric', // name of the measurement + 0.64, // the measurement value + ['host' => 'server01', 'region' => 'us-west'], // optional tags + ['cpucount' => 10], // optional additional fields 1435255849 // Time precision has to be set to seconds! ), new Point( - 'test_metric', - 0.84, - ['host' => 'server01', 'region' => 'us-west'], - array('cpucount' => 10), - 1435255850 // Time precision has to be set to seconds! + 'test_metric', // name of the measurement + 0.84, // the measurement value + ['host' => 'server01', 'region' => 'us-west'], // optional tags + ['cpucount' => 10], // optional additional fields + 1435255849 // Time precision has to be set to seconds! ) ); @@ -115,6 +115,28 @@ measurements to InfluxDB. The point class allows one to easily write data in bat The name of a measurement and the value are mandatory. Additional fields, tags and a timestamp are optional. InfluxDB takes the current time as the default timestamp. +You can also write multiple fields to a measurement without specifying a value: + +```php + $points = [ + new Point( + 'instance', // the name of the measurement + null, // measurement value + ['host' => 'server01', 'region' => 'us-west'], // measurement tags + ['cpucount' => 10, 'free' => 1], // measurement fields + exec('date +%s%N') // timestamp in nanoseconds + ), + new Point( + 'instance', // the name of the measurement + null, // measurement value + ['host' => 'server01', 'region' => 'us-west'], // measurement tags + ['cpucount' => 10, 'free' => 2], // measurement fields + exec('date +%s%N') // timestamp in nanoseconds + ) + ]; + +``` + #### Writing data using udp First, set your InfluxDB host to support incoming UDP sockets: diff --git a/src/InfluxDB/Point.php b/src/InfluxDB/Point.php index 17c3f72e5..59d332086 100644 --- a/src/InfluxDB/Point.php +++ b/src/InfluxDB/Point.php @@ -44,7 +44,7 @@ class Point */ public function __construct( $measurement, - $value, + $value = null, array $tags = array(), array $additionalFields = array(), $timestamp = null @@ -57,7 +57,9 @@ class Point $this->tags = $tags; $this->fields = $additionalFields; - $this->fields['value'] = (float) $value; + if ($value) { + $this->fields['value'] = (float) $value; + } if ($timestamp && !$this->isValidTimeStamp($timestamp)) { throw new DatabaseException(sprintf('%s is not a valid timestamp', $timestamp)); From a6b4616d0da909a42b45adde730b0bf831a83aa8 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 23 Jul 2015 09:40:41 +0200 Subject: [PATCH 68/72] Properly fixed exceptions --- src/InfluxDB/Client.php | 2 +- src/InfluxDB/Database.php | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index faec328cf..2c8b614fa 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -170,7 +170,7 @@ class Client return $driver->query(); } catch (\Exception $e) { - throw new Exception(sprintf('Query has failed, exception: %s', $e->getMessage())); + throw new Exception('Query has failed', $e->getCode(), $e); } } diff --git a/src/InfluxDB/Database.php b/src/InfluxDB/Database.php index e75300261..515fb1cb5 100644 --- a/src/InfluxDB/Database.php +++ b/src/InfluxDB/Database.php @@ -93,7 +93,9 @@ class Database } } catch (\Exception $e) { throw new DatabaseException( - sprintf('Failed to created database %s, exception: %s', $this->name, $e->getMessage()) + sprintf('Failed to created database %s', $this->name), + $e->getCode(), + $e ); } } @@ -138,7 +140,7 @@ class Database return $driver->isSuccess(); } catch (\Exception $e) { - throw new Exception(sprintf('Writing has failed, exception: %s', $e->getMessage())); + throw new Exception('Writing has failed', $e->getCode(), $e); } } From b6eff42ac677f98efeb8dc71eece35325dd97d2b Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 23 Jul 2015 09:42:05 +0200 Subject: [PATCH 69/72] Modified README.MD --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cadad51ea..b367933a4 100644 --- a/README.md +++ b/README.md @@ -269,7 +269,7 @@ Some functions are too general for a database. So these are available in the cli ## Changelog ####1.0.0 -* Dropped support for php 5.3 and php 5.4 +* -BREAKING CHANGE- Dropped support for PHP 5.3 and PHP 5.4 * Allowing for custom drivers * UDP support From 25fa2b02a19d440b1dbfdd458d68330c51b567a1 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Thu, 23 Jul 2015 10:11:13 +0200 Subject: [PATCH 70/72] Updated README.MD --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index b367933a4..9705151f8 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,11 @@ Installation can be done with composer: composer require influxdb/influxdb-php:dev-master +### NOTE for PHP 5.3 and PHP 5.4 users + +If you use either PHP 5.3 and PHP 5.4, the 0.1.x release is still supported (bug fixes and new release fixes). +The 0.1.x branch will work on PHP 5.3 and PHP 5.4 but doesn't contain all the features that the 1.0.0 release has such as UDP support. + ### Getting started Initialize a new client object: From 891a6705d8c2b2b296010bcef1c3d392b4398f8b Mon Sep 17 00:00:00 2001 From: Jamie Hall Date: Wed, 29 Jul 2015 10:19:34 +0200 Subject: [PATCH 71/72] Updated Point.php to stop converting value to float Converting a value to a float causes a conflict "field type conflict: input field "value" on measurement "datapoints" is type int64, already exists as type float". For example, If i send 2.01, it works, if I send 2.00, it converts it into 2 and then Influxdb treats it as an integer. --- src/InfluxDB/Point.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/InfluxDB/Point.php b/src/InfluxDB/Point.php index 59d332086..cd757e209 100644 --- a/src/InfluxDB/Point.php +++ b/src/InfluxDB/Point.php @@ -58,7 +58,7 @@ class Point $this->fields = $additionalFields; if ($value) { - $this->fields['value'] = (float) $value; + $this->fields['value'] = $value; } if ($timestamp && !$this->isValidTimeStamp($timestamp)) { From 969829296c266bf50faa589a5feaadc267486e60 Mon Sep 17 00:00:00 2001 From: Stephen Hoogendijk Date: Sun, 2 Aug 2015 22:13:17 +0200 Subject: [PATCH 72/72] Added admin functionality; allowed user credentials in guzzle driver --- README.md | 55 +++++++- src/InfluxDB/Client.php | 66 +++++---- src/InfluxDB/Client/Admin.php | 158 ++++++++++++++++++++++ src/InfluxDB/Database.php | 16 ++- src/InfluxDB/Driver/DriverInterface.php | 1 - src/InfluxDB/Driver/Guzzle.php | 33 ++++- tests/unit/AbstractTest.php | 124 +++++++++++++++++ tests/unit/AdminTest.php | 72 ++++++++++ tests/unit/ClientTest.php | 27 ++-- tests/unit/DatabaseTest.php | 56 +------- tests/unit/result-test-users.example.json | 24 ++++ 11 files changed, 532 insertions(+), 100 deletions(-) create mode 100644 src/InfluxDB/Client/Admin.php create mode 100644 tests/unit/AbstractTest.php create mode 100644 tests/unit/AdminTest.php create mode 100644 tests/unit/result-test-users.example.json diff --git a/README.md b/README.md index 9705151f8..06f60943a 100644 --- a/README.md +++ b/README.md @@ -262,9 +262,58 @@ Some functions are too general for a database. So these are available in the cli $result = $client->listDatabases(); ``` +### Admin functionality + +You can use the client's $client->admin functionality to administer InfluxDB via the API. + +```php + // add a new user without privileges + $client->admin->createUser('testuser123', 'testpassword'); + + // add a new user with ALL cluster-wide privileges + $client->admin->createUser('admin_user', 'password', \InfluxDB\Client\Admin::PRIVILEGE_ALL); + + // drop user testuser123 + $client->admin->dropUser('testuser123'); +``` + +List all the users: + +```php + // show a list of all users + $results = $client->admin->showUsers(); + + // show users returns a ResultSet object + $users = $results->getPoints(); +``` + +#### Granting and revoking privileges + +Granting permissions can be done on both the database level and cluster-wide. +To grant a user specific privileges on a database, provide a database object or a database name. + +```php + + // grant permissions using a database object + $database = $client->selectDB('test_db'); + $client->admin->grant(\InfluxDB\Client\Admin::PRIVILEGE_READ, 'testuser123', $database); + + // give user testuser123 read privileges on database test_db + $client->admin->grant(\InfluxDB\Client\Admin::PRIVILEGE_READ, 'testuser123', 'test_db'); + + // revoke user testuser123's read privileges on database test_db + $client->admin->revoke(\InfluxDB\Client\Admin::PRIVILEGE_READ, 'testuser123', 'test_db'); + + // grant a user cluster-wide privileges + $client->admin->grant(\InfluxDB\Client\Admin::PRIVILEGE_READ, 'testuser123'); + + // Revoke an admin's cluster-wide privileges + $client->admin->revoke(\InfluxDB\Client\Admin::PRIVILEGE_ALL, 'admin_user'); + +``` + ## Todo -* Add more admin features * More unit tests * Increase documentation (wiki?) * Add more features to the query builder @@ -273,6 +322,10 @@ Some functions are too general for a database. So these are available in the cli ## Changelog +####1.0.1 +* Added support for authentication in the guzzle driver +* Added admin functionality + ####1.0.0 * -BREAKING CHANGE- Dropped support for PHP 5.3 and PHP 5.4 * Allowing for custom drivers diff --git a/src/InfluxDB/Client.php b/src/InfluxDB/Client.php index 2c8b614fa..b724c63f0 100644 --- a/src/InfluxDB/Client.php +++ b/src/InfluxDB/Client.php @@ -2,8 +2,10 @@ namespace InfluxDB; +use InfluxDB\Client\Admin; use InfluxDB\Client\Exception as ClientException; use InfluxDB\Driver\DriverInterface; +use InfluxDB\Driver\Exception as DriverException; use InfluxDB\Driver\Guzzle; use InfluxDB\Driver\QueryDriverInterface; use InfluxDB\Driver\UDP; @@ -16,6 +18,11 @@ use InfluxDB\Driver\UDP; */ class Client { + /** + * @var Admin + */ + public $admin; + /** * @var string */ @@ -124,6 +131,8 @@ class Client ] ) ); + + $this->admin = new Admin($this); } /** @@ -142,11 +151,12 @@ class Client * * @param string $database * @param string $query - * @param array $params + * @param array $parameters + * * @return ResultSet * @throws Exception */ - public function query($database, $query, $params = []) + public function query($database, $query, $parameters = []) { if (!$this->driver instanceof QueryDriverInterface) { @@ -154,22 +164,29 @@ class Client } if ($database) { - $params['db'] = $database; + $parameters['db'] = $database; } $driver = $this->getDriver(); - $driver->setParameters([ - 'url' => 'query?' . http_build_query(array_merge(['q' => $query], $params)), - 'database' => $database, - 'method' => 'get' - ]); + $parameters = [ + 'url' => 'query?' . http_build_query(array_merge(['q' => $query], $parameters)), + 'database' => $database, + 'method' => 'get' + ]; + + // add authentication to the driver if needed + if (!empty($this->username) && !empty($this->password)) { + $parameters += ['auth' => [$this->username, $this->password]]; + } + + $driver->setParameters($parameters); try { // perform the query and return the resultset return $driver->query(); - } catch (\Exception $e) { + } catch (DriverException $e) { throw new Exception('Query has failed', $e->getCode(), $e); } } @@ -265,21 +282,6 @@ class Client return $this->timeout; } - /** - * @param Point[] $points - * @return array - */ - protected function pointsToArray(array $points) - { - $names = []; - - foreach ($points as $item) { - $names[] = $item['name']; - } - - return $names; - } - /** * @param Driver\DriverInterface $driver */ @@ -303,4 +305,20 @@ class Client { return $this->host; } + + /** + * @param Point[] $points + * @return array + */ + protected function pointsToArray(array $points) + { + $names = []; + + foreach ($points as $item) { + $names[] = $item['name']; + } + + return $names; + } + } diff --git a/src/InfluxDB/Client/Admin.php b/src/InfluxDB/Client/Admin.php new file mode 100644 index 000000000..b62782a38 --- /dev/null +++ b/src/InfluxDB/Client/Admin.php @@ -0,0 +1,158 @@ +client = $client; + } + + /** + * Create a user + * + * @param string $username + * @param string $password + * + * @param string $privilege + * + * @throws \InfluxDB\Exception + * @return \InfluxDB\ResultSet + */ + public function createUser($username, $password, $privilege = null) + { + $query = sprintf('CREATE USER %s WITH PASSWORD \'%s\'', $username, $password); + + if ($privilege) { + $query .= " WITH $privilege PRIVILEGES"; + } + + return $this->client->query(null, $query); + } + + /** + * @param string $username + * + * @return \InfluxDB\ResultSet + * @throws \InfluxDB\Exception + */ + public function dropUser($username) + { + return $this->client->query(null, 'DROP USER ' . $username); + } + + /** + * Change a users password + * + * @param string $username + * @param string $newPassword + * + * @return \InfluxDB\ResultSet + * @throws \InfluxDB\Exception + */ + public function changeUserPassword($username, $newPassword) + { + return $this->client->query(null, "SET PASSWORD FOR $username = '$newPassword'"); + } + + /** + * Shows a list of all the users + * + * @return \InfluxDB\ResultSet + * @throws \InfluxDB\Exception + */ + public function showUsers() + { + return $this->client->query(null, "SHOW USERS"); + } + + /** + * Grants permissions + * + * @param string $privilege + * @param string $username + * @param Database|string $database + * + * @return \InfluxDB\ResultSet + */ + public function grant($privilege, $username, $database = null) + { + return $this->executePrivilege('GRANT', $privilege, $username, $database); + } + + /** + * Revokes permissions + * + * @param string $privilege + * @param string $username + * @param Database|string $database + * + * @throws \InfluxDB\Exception + * @return \InfluxDB\ResultSet + */ + public function revoke($privilege, $username, $database = null) + { + return $this->executePrivilege('REVOKE', $privilege, $username, $database); + } + + /** + * @param string $type + * @param string $privilege + * @param string $username + * @param Database|string $database + * + * @throws \InfluxDB\Exception + * @return \InfluxDB\ResultSet + */ + private function executePrivilege($type, $privilege, $username, $database = null) + { + + if (!in_array($privilege, [self::PRIVILEGE_READ, self::PRIVILEGE_WRITE, self::PRIVILEGE_ALL])) { + throw new Exception($privilege . ' is not a valid privileges, allowed privileges: READ, WRITE, ALL'); + } + + if ($privilege != self::PRIVILEGE_ALL && !$database) { + throw new Exception('Only grant ALL cluster-wide privileges are allowed'); + } + + $database = ($database instanceof Database ? $database->getName() : (string) $database); + + $query = "$type $privilege"; + + if ($database) { + $query .= sprintf(' ON %s ', $database); + } else { + $query .= " PRIVILEGES "; + } + + if ($username && $type == 'GRANT') { + $query .= "TO $username"; + } elseif ($username && $type == 'REVOKE') { + $query .= "FROM $username"; + } + + return $this->client->query(null, $query); + } +} \ No newline at end of file diff --git a/src/InfluxDB/Database.php b/src/InfluxDB/Database.php index 515fb1cb5..3ca7163f8 100644 --- a/src/InfluxDB/Database.php +++ b/src/InfluxDB/Database.php @@ -9,8 +9,6 @@ use InfluxDB\Query\Builder as QueryBuilder; /** * Class Database * - * @todo admin functionality - * * @package InfluxDB * @author Stephen "TheCodeAssassin" Hoogendijk */ @@ -128,11 +126,19 @@ class Database try { $driver = $this->client->getDriver(); - $driver->setParameters([ + + $parameters = [ 'url' => sprintf('write?db=%s&precision=%s', $this->name, $precision), 'database' => $this->name, 'method' => 'post' - ]); + ]; + + // add authentication to the driver if needed + if (!empty($this->username) && !empty($this->password)) { + $parameters += ['auth' => [$this->username, $this->password]]; + } + + $driver->setParameters($parameters); // send the points to influxDB $driver->write(implode(PHP_EOL, $payload)); @@ -140,7 +146,7 @@ class Database return $driver->isSuccess(); } catch (\Exception $e) { - throw new Exception('Writing has failed', $e->getCode(), $e); + throw new Exception($e->getMessage(), $e->getCode()); } } diff --git a/src/InfluxDB/Driver/DriverInterface.php b/src/InfluxDB/Driver/DriverInterface.php index 5400ba051..fc3a2c2f9 100644 --- a/src/InfluxDB/Driver/DriverInterface.php +++ b/src/InfluxDB/Driver/DriverInterface.php @@ -13,7 +13,6 @@ namespace InfluxDB\Driver; interface DriverInterface { - /** * Called by the client write() method, will pass an array of required parameters such as db name * diff --git a/src/InfluxDB/Driver/Guzzle.php b/src/InfluxDB/Driver/Guzzle.php index d014c1f3b..a3f1d9111 100644 --- a/src/InfluxDB/Driver/Guzzle.php +++ b/src/InfluxDB/Driver/Guzzle.php @@ -7,6 +7,7 @@ namespace InfluxDB\Driver; use GuzzleHttp\Client; use Guzzle\Http\Message\Response; +use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Psr7\Request; use InfluxDB\ResultSet; @@ -77,18 +78,26 @@ class Guzzle implements DriverInterface, QueryDriverInterface */ public function write($data = null) { - $this->response = $this->httpClient->post($this->parameters['url'], ['body' => $data]); + $this->response = $this->httpClient->post($this->parameters['url'], $this->getRequestParameters($data)); } /** + * @throws Exception * @return ResultSet */ public function query() { - $response = $this->httpClient->get($this->parameters['url']); + + $response = $this->httpClient->get($this->parameters['url'], $this->getRequestParameters()); $raw = (string) $response->getBody(); + $responseJson = json_encode($raw); + + if (isset($responseJson->error)) { + throw new Exception($responseJson->error); + } + return new ResultSet($raw); } @@ -102,4 +111,24 @@ class Guzzle implements DriverInterface, QueryDriverInterface { return in_array($this->response->getStatusCode(), ['200', '204']); } + + /** + * @param null $data + * + * @return array + */ + protected function getRequestParameters($data = null) + { + $requestParameters = ['http_errors' => false]; + + if ($data) { + $requestParameters += ['body' => $data]; + } + + if (isset($this->parameters['auth'])) { + $requestParameters += ['auth' => $this->parameters['auth']]; + } + + return $requestParameters; + } } diff --git a/tests/unit/AbstractTest.php b/tests/unit/AbstractTest.php new file mode 100644 index 000000000..160f6aea6 --- /dev/null +++ b/tests/unit/AbstractTest.php @@ -0,0 +1,124 @@ +mockClient = $this->getMockBuilder('\InfluxDB\Client') + ->disableOriginalConstructor() + ->getMock(); + + $this->resultData = file_get_contents(dirname(__FILE__) . '/result.example.json'); + + $this->mockClient->expects($this->any()) + ->method('getBaseURI') + ->will($this->returnValue($this->equalTo('http://localhost:8086'))); + + $this->mockClient->expects($this->any()) + ->method('query') + ->will($this->returnValue(new ResultSet($this->resultData))); + + $httpMockClient = new Guzzle($this->buildHttpMockClient('')); + + // make sure the client has a valid driver + $this->mockClient->expects($this->any()) + ->method('getDriver') + ->will($this->returnValue($httpMockClient)); + + $this->database = new Database('influx_test_db', $this->mockClient); + + } + + /** + * @return mixed + */ + public function getMockResultSet() + { + return $this->mockResultSet; + } + + /** + * @param mixed $mockResultSet + */ + public function setMockResultSet($mockResultSet) + { + $this->mockResultSet = $mockResultSet; + } + + + /** + * @return GuzzleClient + */ + public function buildHttpMockClient($body) + { + // Create a mock and queue two responses. + $mock = new MockHandler([new Response(200, array(), $body)]); + + $handler = HandlerStack::create($mock); + return new GuzzleClient(['handler' => $handler]); + } + + /** + * @return string + */ + public function getEmptyResult() + { + return $this->emptyResult; + } + + /** + * @param bool $emptyResult + * + * @return PHPUnit_Framework_MockObject_MockObject|Client + */ + public function getClientMock($emptyResult = false) + { + $mockClient = $this->getMockBuilder('\InfluxDB\Client') + ->disableOriginalConstructor() + ->getMock(); + + if ($emptyResult) { + $mockClient->expects($this->once()) + ->method('query') + ->will($this->returnValue(new ResultSet($this->getEmptyResult()))); + } + + return $mockClient; + } +} \ No newline at end of file diff --git a/tests/unit/AdminTest.php b/tests/unit/AdminTest.php new file mode 100644 index 000000000..889874f4c --- /dev/null +++ b/tests/unit/AdminTest.php @@ -0,0 +1,72 @@ +getAdminObject(true); + + $this->assertEquals( + new ResultSet($this->emptyResult), + $adminObject->createUser('test', 'test', Client\Admin::PRIVILEGE_ALL) + ); + } + + public function testChangeUserPassword() + { + $adminObject = $this->getAdminObject(true); + + $this->assertEquals( + new ResultSet($this->emptyResult), + $adminObject->changeUserPassword('test', 'test') + ); + } + + public function testShowUsers() + { + $testJson = file_get_contents(dirname(__FILE__) . '/result-test-users.example.json'); + + $clientMock = $this->getClientMock(); + $testResult = new ResultSet($testJson); + + $clientMock->expects($this->once()) + ->method('query') + ->will($this->returnValue($testResult)); + + $adminMock = new Client\Admin($clientMock); + + $this->assertEquals($testResult, $adminMock->showUsers()); + } + + /** + * @return Client\Admin + */ + private function getAdminObject() + { + return new Client\Admin($this->getClientMock(true)); + } + +} \ No newline at end of file diff --git a/tests/unit/ClientTest.php b/tests/unit/ClientTest.php index 095d534b0..09f420d1b 100644 --- a/tests/unit/ClientTest.php +++ b/tests/unit/ClientTest.php @@ -2,16 +2,20 @@ namespace InfluxDB\Test; -use GuzzleHttp\Client as GuzzleClient; -use GuzzleHttp\Handler\MockHandler; -use GuzzleHttp\HandlerStack; -use GuzzleHttp\Psr7\Response; use InfluxDB\Client; use InfluxDB\Driver\Guzzle; -class ClientTest extends \PHPUnit_Framework_TestCase +class ClientTest extends AbstractTest { + /** + * + */ + public function setUp() + { + parent::setUp(); + } + /** @var Client $client */ protected $client = null; @@ -43,7 +47,7 @@ class ClientTest extends \PHPUnit_Framework_TestCase $query = "some-bad-query"; $bodyResponse = file_get_contents(dirname(__FILE__) . '/result.example.json'); - $httpMockClient = self::buildHttpMockClient($bodyResponse); + $httpMockClient = $this->buildHttpMockClient($bodyResponse); $client->setDriver(new Guzzle($httpMockClient)); @@ -53,15 +57,4 @@ class ClientTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('\InfluxDB\ResultSet', $result); } - /** - * @return GuzzleClient - */ - public static function buildHttpMockClient($body) - { - // Create a mock and queue two responses. - $mock = new MockHandler([new Response(200, array(), $body)]); - - $handler = HandlerStack::create($mock); - return new GuzzleClient(['handler' => $handler]); - } } \ No newline at end of file diff --git a/tests/unit/DatabaseTest.php b/tests/unit/DatabaseTest.php index 25fcd1cf7..e41038547 100644 --- a/tests/unit/DatabaseTest.php +++ b/tests/unit/DatabaseTest.php @@ -10,30 +10,14 @@ use InfluxDB\ResultSet; use PHPUnit_Framework_MockObject_MockObject; use PHPUnit_Framework_TestCase; -class DatabaseTest extends PHPUnit_Framework_TestCase +class DatabaseTest extends AbstractTest { - /** @var Database $db */ - protected $db = null; - - /** @var Client|PHPUnit_Framework_MockObject_MockObject $client */ - protected $mockClient; - /** * @var string */ protected $dataToInsert; - /** - * @var string - */ - protected $resultData; - - /** - * @var string - */ - static $emptyResult = '{"results":[{}]}'; - /** * @var */ @@ -41,34 +25,14 @@ class DatabaseTest extends PHPUnit_Framework_TestCase public function setUp() { - $this->mockClient = $this->getMockBuilder('\InfluxDB\Client') - ->disableOriginalConstructor() - ->getMock(); + parent::setUp(); $this->resultData = file_get_contents(dirname(__FILE__) . '/result.example.json'); - $this->mockClient->expects($this->any()) - ->method('getBaseURI') - ->will($this->returnValue($this->equalTo('http://localhost:8086'))); - - $this->mockClient->expects($this->any()) - ->method('query') - ->will($this->returnValue(new ResultSet($this->resultData))); - - $this->mockClient->expects($this->any()) ->method('listDatabases') ->will($this->returnValue(array('test123', 'test'))); - $httpMockClient = new Guzzle(ClientTest::buildHttpMockClient('')); - - // make sure the client has a valid driver - $this->mockClient->expects($this->any()) - ->method('getDriver') - ->will($this->returnValue($httpMockClient)); - - $this->db = new Database('influx_test_db', $this->mockClient); - $this->dataToInsert = file_get_contents(dirname(__FILE__) . '/input.example.json'); } @@ -79,26 +43,18 @@ class DatabaseTest extends PHPUnit_Framework_TestCase public function testQuery() { $testResultSet = new ResultSet($this->resultData); - $this->assertEquals($this->db->query('SELECT * FROM test_metric'), $testResultSet); + $this->assertEquals($this->database->query('SELECT * FROM test_metric'), $testResultSet); } public function testCreateRetentionPolicy() { $retentionPolicy = new Database\RetentionPolicy('test', '1d', 1, true); - $mockClient = $this->getMockBuilder('\InfluxDB\Client') - ->disableOriginalConstructor() - ->getMock(); - - $mockClient->expects($this->once()) - ->method('query') - ->will($this->returnValue(new ResultSet(self::$emptyResult))); - - + $mockClient = $this->getClientMock(true); $database = new Database('test', $mockClient); - $this->assertEquals($database->createRetentionPolicy($retentionPolicy), new ResultSet(self::$emptyResult)); + $this->assertEquals($database->createRetentionPolicy($retentionPolicy), new ResultSet($this->getEmptyResult())); } /** @@ -139,6 +95,6 @@ class DatabaseTest extends PHPUnit_Framework_TestCase 0.84 ); - $this->assertEquals(true, $this->db->writePoints(array($point1, $point2))); + $this->assertEquals(true, $this->database->writePoints(array($point1, $point2))); } } \ No newline at end of file diff --git a/tests/unit/result-test-users.example.json b/tests/unit/result-test-users.example.json new file mode 100644 index 000000000..34f5f999b --- /dev/null +++ b/tests/unit/result-test-users.example.json @@ -0,0 +1,24 @@ +{ + "results": [ + { + "series": [ + { + "columns": [ + "user", + "admin" + ], + "values": [ + [ + "test1", + true + ], + [ + "test2", + false + ] + ] + } + ] + } + ] +} \ No newline at end of file