From 1ab3c85047c2eeda5988ef9aee74f625edc941af Mon Sep 17 00:00:00 2001 From: Andrew Oblikov Date: Mon, 20 Aug 2018 17:24:49 +0300 Subject: [PATCH 1/3] init --- .gitignore | 2 + README.md | 87 + composer.json | 27 + composer.lock | 2217 +++++++++++++++++++++ phpunit.xml | 16 + src/Client.php | 129 ++ src/Exception/NotImplementedException.php | 10 + src/Exception/QueryException.php | 8 + src/Query/Builder.php | 8 + src/Query/ExecuteQuery.php | 26 + src/Query/Grammar.php | 45 + src/Query/InsertQuery.php | 68 + src/Query/Query.php | 134 ++ src/Query/QueryInterface.php | 14 + src/Query/SelectQuery.php | 22 + src/Settings.php | 237 +++ src/Statement.php | 209 ++ src/System.php | 199 ++ src/Transport/Http.php | 177 ++ src/Transport/TransportInterface.php | 41 + tests/ClientTest.php | 157 ++ 21 files changed, 3833 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 phpunit.xml create mode 100644 src/Client.php create mode 100644 src/Exception/NotImplementedException.php create mode 100644 src/Exception/QueryException.php create mode 100644 src/Query/Builder.php create mode 100644 src/Query/ExecuteQuery.php create mode 100644 src/Query/Grammar.php create mode 100644 src/Query/InsertQuery.php create mode 100644 src/Query/Query.php create mode 100644 src/Query/QueryInterface.php create mode 100644 src/Query/SelectQuery.php create mode 100644 src/Settings.php create mode 100644 src/Statement.php create mode 100644 src/System.php create mode 100644 src/Transport/Http.php create mode 100644 src/Transport/TransportInterface.php create mode 100644 tests/ClientTest.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e0caea8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/ +vendor/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..19119ba --- /dev/null +++ b/README.md @@ -0,0 +1,87 @@ +# PHP Client for ClickHouse columnar DBMS +https://clickhouse.yandex + + +## Документация +https://clickhouse.readme.io/ + +## Создание клиента + +$client = new \ClickHouse\Client('http://127.0.0.1', 8123); + + +## Проверка сервера + +$bool = $client->ping(); + +## Выполнить SELECT запрос + +$client->select($sql, $params); + +$sql - строка с sql запросом +$params - массив для биндинга параметров + +Возвращает объект типа Statement + +### интерфейс Statement + +getRawResult возвращает данные в сыром виде, так как их вернул сервер. + +getResult возвращает данные в виде объекта stdClass + +getMeta возвращает метаданные. типы столбцов и тд + +getTotals - тотальные значения (при использовании WITH TOTALS в запросе). + +getExtremes - экстремальные значения (при настройке extremes, выставленной в 1). + +getRows - общее количество выведенных строчек. + +getRowsBeforeLimitAtLeast - не менее скольких строчек получилось бы, если бы не было LIMIT-а. Выводится только если запрос содержит LIMIT. + +fetchAll - возвращает массив со всеми строками + +fetchOne - возвращает первую строку + +fetchColumn - возвращает значение указанного столбца + +## Выполнить INSERT запрос + +$client->insert($table, $columns = [], $values); + +## Выполнить BATCH INSERT запрос + +## Выполнить ALTER/CREATE/DROP запросы + +$client->execute($sql); + +## Системные запросы + +### tables + +Информация о таблицах, содержит столбцы database, name, engine типа String. + +$client->system()->tables(); + +### databases + +Информация о базах + +$client->system()->databases(); + + +### clusters + + информация о доступных в конфигурационном файле кластерах и серверах, которые в них входят. + +$client->system()->clusters(); + + +### остальное скоро будет здесь + + +## Настройки + +$client->settings()->max_memory_usage; //получить значение настроки + +$client->settings()->max_memory_usage = 10G; //изменить настройку для текущий сессии diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..7f6f63f --- /dev/null +++ b/composer.json @@ -0,0 +1,27 @@ +{ + "name": "8bitov/clickhouse-php-client", + "license": "MIT", + "version" : "0.0.3", + "keywords": ["clickhouse", "driver", "client", "http"], + "homepage": "https://github.com/8bitov/doctrine2-clickhouse", + "authors": [ + { + "name": "Aleksey Kuznetsov" + } + ], + "require": { + "php": ">=5.5.0", + "guzzlehttp/guzzle": "~6.0" + }, + "require-dev": { + "phpunit/phpunit": "~5.4.6", + "mockery/mockery": "~0.9", + "satooshi/php-coveralls": "~1.0", + "fzaninotto/faker": "^1.6" + }, + "autoload": { + "psr-4": { + "ClickHouse\\": "src/" + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..8d2ecc5 --- /dev/null +++ b/composer.lock @@ -0,0 +1,2217 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "9a8cc9073a0c3b1365b3b21067697fc9", + "content-hash": "0d9ad4dad80b949ac6c41123933a9369", + "packages": [ + { + "name": "guzzlehttp/guzzle", + "version": "6.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "d094e337976dff9d8e2424e8485872194e768662" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d094e337976dff9d8e2424e8485872194e768662", + "reference": "d094e337976dff9d8e2424e8485872194e768662", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "~1.0", + "guzzlehttp/psr7": "~1.1", + "php": ">=5.5.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0", + "psr/log": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.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": "2016-03-21 20:02:09" + }, + { + "name": "guzzlehttp/promises", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579", + "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579", + "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": "2016-05-18 16:56:05" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", + "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", + "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.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "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": "PSR-7 message implementation", + "keywords": [ + "http", + "message", + "stream", + "uri" + ], + "time": "2016-06-24 23:00:38" + }, + { + "name": "psr/http-message", + "version": "1.0", + "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": [ + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14 21:17:01" + }, + { + "name": "fzaninotto/faker", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/44f9a286a04b80c76a4e5fb7aad8bb539b920123", + "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123", + "shasum": "" + }, + "require": { + "php": "^5.3.3|^7.0" + }, + "require-dev": { + "ext-intl": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "extra": { + "branch-alias": [] + }, + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "time": "2016-04-29 12:21:54" + }, + { + "name": "guzzle/guzzle", + "version": "v3.9.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle3.git", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9", + "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-03-18 18:23:50" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "v1.2.2", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/b37020aa976fa52d3de9aa904aa2522dc518f79c", + "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "1.3.3", + "satooshi/php-coveralls": "dev-master" + }, + "type": "library", + "autoload": { + "classmap": [ + "hamcrest" + ], + "files": [ + "hamcrest/Hamcrest.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "time": "2015-05-11 14:41:42" + }, + { + "name": "mockery/mockery", + "version": "0.9.5", + "source": { + "type": "git", + "url": "https://github.com/padraic/mockery.git", + "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/padraic/mockery/zipball/4db079511a283e5aba1b3c2fb19037c645e70fc2", + "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "~1.1", + "lib-pcre": ">=7.0", + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.9.x-dev" + } + }, + "autoload": { + "psr-0": { + "Mockery": "library/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "http://blog.astrumfutura.com" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "http://davedevelopment.co.uk" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.", + "homepage": "http://github.com/padraic/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "time": "2016-05-22 21:52:33" + }, + { + "name": "myclabs/deep-copy", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "a8773992b362b58498eed24bf85005f363c34771" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/a8773992b362b58498eed24bf85005f363c34771", + "reference": "a8773992b362b58498eed24bf85005f363c34771", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "doctrine/collections": "1.*", + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "homepage": "https://github.com/myclabs/DeepCopy", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2015-11-20 12:04:31" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2015-12-27 11:43:31" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "9270140b940ff02e58ec577c237274e92cd40cdd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd", + "reference": "9270140b940ff02e58ec577c237274e92cd40cdd", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.2.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2016-06-10 09:48:41" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443", + "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2016-06-10 07:14:17" + }, + { + "name": "phpspec/prophecy", + "version": "v1.6.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "58a8137754bc24b25740d4281399a4a3596058e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", + "reference": "58a8137754bc24b25740d4281399a4a3596058e0", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "sebastian/comparator": "^1.1", + "sebastian/recursion-context": "^1.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2016-06-07 08:13:47" + }, + { + "name": "phpunit/php-code-coverage", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "900370c81280cc0d942ffbc5912d80464eaee7e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/900370c81280cc0d942ffbc5912d80464eaee7e9", + "reference": "900370c81280cc0d942ffbc5912d80464eaee7e9", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "^1.4.2", + "sebastian/code-unit-reverse-lookup": "~1.0", + "sebastian/environment": "^1.3.2", + "sebastian/version": "~1.0|~2.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "^5.4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.4.0", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2016-06-03 05:03:56" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2015-06-21 13:08:43" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21 13:50:34" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4|~5" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2016-05-12 18:03:57" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-09-15 10:49:45" + }, + { + "name": "phpunit/phpunit", + "version": "5.4.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "2f1fc94b77ea6418bd6a06c64a1dac0645fbce59" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2f1fc94b77ea6418bd6a06c64a1dac0645fbce59", + "reference": "2f1fc94b77ea6418bd6a06c64a1dac0645fbce59", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "myclabs/deep-copy": "~1.3", + "php": "^5.6 || ^7.0", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "^4.0", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "^3.2", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.2", + "sebastian/environment": "^1.3 || ^2.0", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/object-enumerator": "~1.0", + "sebastian/resource-operations": "~1.0", + "sebastian/version": "~1.0|~2.0", + "symfony/yaml": "~2.1|~3.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2016-06-16 06:01:15" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "3.2.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "b13d0d9426ced06958bd32104653526a6c998a52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/b13d0d9426ced06958bd32104653526a6c998a52", + "reference": "b13d0d9426ced06958bd32104653526a6c998a52", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.6 || ^7.0", + "phpunit/php-text-template": "^1.2", + "sebastian/exporter": "^1.2" + }, + "conflict": { + "phpunit/phpunit": "<5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2016-06-12 07:37:26" + }, + { + "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": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/satooshi/php-coveralls.git", + "reference": "da51d304fe8622bf9a6da39a8446e7afd432115c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/da51d304fe8622bf9a6da39a8446e7afd432115c", + "reference": "da51d304fe8622bf9a6da39a8446e7afd432115c", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-simplexml": "*", + "guzzle/guzzle": "^2.8|^3.0", + "php": ">=5.3.3", + "psr/log": "^1.0", + "symfony/config": "^2.1|^3.0", + "symfony/console": "^2.1|^3.0", + "symfony/stopwatch": "^2.0|^3.0", + "symfony/yaml": "^2.0|^3.0" + }, + "suggest": { + "symfony/http-kernel": "Allows Symfony integration" + }, + "bin": [ + "bin/coveralls" + ], + "type": "library", + "autoload": { + "psr-4": { + "Satooshi\\": "src/Satooshi/" + } + }, + "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": "2016-01-20 17:35:46" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/c36f5e7cfce482fde5bf8d10d41a53591e0198fe", + "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2016-02-13 06:45:14" + }, + { + "name": "sebastian/comparator", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-07-26 15:48:44" + }, + { + "name": "sebastian/diff", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-12-08 07:14:41" + }, + { + "name": "sebastian/environment", + "version": "1.3.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716", + "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-05-17 03:18:57" + }, + { + "name": "sebastian/exporter", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2016-06-17 09:04:28" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12 03:26:01" + }, + { + "name": "sebastian/object-enumerator", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "d4ca2fb70344987502567bc50081c03e6192fb26" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26", + "reference": "d4ca2fb70344987502567bc50081c03e6192fb26", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2016-01-28 13:25:10" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-11-11 19:50:13" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28 20:34:47" + }, + { + "name": "sebastian/version", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", + "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-02-04 12:56:52" + }, + { + "name": "symfony/config", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "048dc47e07f92333203c3b7045868bbc864fc40e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/048dc47e07f92333203c3b7045868bbc864fc40e", + "reference": "048dc47e07f92333203c3b7045868bbc864fc40e", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/filesystem": "~2.8|~3.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "2016-05-20 11:48:17" + }, + { + "name": "symfony/console", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "64a4d43b045f07055bb197650159769604cb2a92" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/64a4d43b045f07055bb197650159769604cb2a92", + "reference": "64a4d43b045f07055bb197650159769604cb2a92", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~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.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "2016-06-14 11:18:07" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.8.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "2a6b8713f8bdb582058cfda463527f195b066110" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2a6b8713f8bdb582058cfda463527f195b066110", + "reference": "2a6b8713f8bdb582058cfda463527f195b066110", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.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/stopwatch": "~2.3|~3.0.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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 EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2016-06-06 11:11:27" + }, + { + "name": "symfony/filesystem", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "5751e80d6f94b7c018f338a4a7be0b700d6f3058" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/5751e80d6f94b7c018f338a4a7be0b700d6f3058", + "reference": "5751e80d6f94b7c018f338a4a7be0b700d6f3058", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "2016-04-12 18:27:47" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "dff51f72b0706335131b00a7f49606168c582594" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", + "reference": "dff51f72b0706335131b00a7f49606168c582594", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2016-05-18 14:26:46" + }, + { + "name": "symfony/stopwatch", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "e7238f98c90b99e9b53f3674a91757228663b04d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/e7238f98c90b99e9b53f3674a91757228663b04d", + "reference": "e7238f98c90b99e9b53f3674a91757228663b04d", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "2016-06-06 11:42:41" + }, + { + "name": "symfony/yaml", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "c5a7e7fc273c758b92b85dcb9c46149ccda89623" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/c5a7e7fc273c758b92b85dcb9c46149ccda89623", + "reference": "c5a7e7fc273c758b92b85dcb9c46149ccda89623", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "2016-06-14 11:18:07" + }, + { + "name": "webmozart/assert", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde", + "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2015-08-24 13:29:44" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.5.0" + }, + "platform-dev": [] +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..988f5d5 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,16 @@ + + + + tests + + + + + src + + + \ No newline at end of file diff --git a/src/Client.php b/src/Client.php new file mode 100644 index 0000000..78d8c94 --- /dev/null +++ b/src/Client.php @@ -0,0 +1,129 @@ +transport = new $transport($host, $port, $username, $password); + + $this->system = new System($this, $settings); + + $this->queryGrammar = new Query\Grammar(); + } + + + /** + * Begin a fluent query against a database table. + * + * @param string $table + * @return \ClickHouse\Query\Builder + */ + public function table($table) + { + return $this->query()->from($table); + } + + /** + * Run a select statement against the database. + * @param string $sql + * @param array $bindings + * @return Statement + * @throws \RuntimeException + */ + public function select($sql, $bindings = []) + { + return $this->transport->select($sql, $bindings); + } + + /** + * @param string $table + * @param array $values + * @param array $columns + * + * @return mixed|void + */ + public function insert($table, $columns = [], $values) + { + return $this->transport->insert($table, $columns, $values); + } + + /** + * @param string $sql + * @param $data + * @param null $formatName + * @return mixed + */ + public function insertBatch($table, $data, $formatName = null) + { + return $this->transport->insertBatch($table, $data, $formatName); + } + + /** + * @param $sql + * @param array $bindings + * @return Statement + */ + public function execute($sql, $bindings = []) + { + return $this->transport->execute($sql, $bindings); + } + + /** + * @return bool + */ + public function ping() + { + $sql = 'SELECT 1 as ping'; + $stm = $this->select($sql); + $ping = $stm->fetchColumn('ping'); + + return $ping === 1; + } + + /** + * @return System + */ + public function system() + { + return $this->system; + } + +} \ No newline at end of file diff --git a/src/Exception/NotImplementedException.php b/src/Exception/NotImplementedException.php new file mode 100644 index 0000000..26d32cb --- /dev/null +++ b/src/Exception/NotImplementedException.php @@ -0,0 +1,10 @@ +init($transport, $sql); + $this->bindParams($bindings); + } + +} \ No newline at end of file diff --git a/src/Query/Grammar.php b/src/Query/Grammar.php new file mode 100644 index 0000000..ba3455b --- /dev/null +++ b/src/Query/Grammar.php @@ -0,0 +1,45 @@ +prepareSql($table, $columns, $values); + $this->init($transport, $sql); + } + + + /** + * @param string $table + * @param array $columns + * @param array $values + * @return string + */ + protected function prepareSql($table, array $columns = [], array $values) + { + $sql = 'INSERT INTO ' . $table; + + if (0 !== count($columns)) { + $sql .= ' (' . implode(',', $columns) . ') '; + } + + $sql .= 'VALUES '; + + + foreach ($values as $row) { + $sql .= ' (' . implode(',', $this->quote($row)) . '), '; + } + + $sql = trim($sql, ', '); + echo $sql, "\n"; + + return $sql; + } + + /** + * @param array $row + * @return array + */ + protected function quote(array $row) + { + $grammar = $this->grammar; + $quote = function ($value) use ($grammar) { + return $grammar->quote($value); + }; + return array_map($quote, $row); + } + +} \ No newline at end of file diff --git a/src/Query/Query.php b/src/Query/Query.php new file mode 100644 index 0000000..3b023b7 --- /dev/null +++ b/src/Query/Query.php @@ -0,0 +1,134 @@ +grammar = new Grammar(); + } + + /** + * @param TransportInterface $transport + * @param string $sql + */ + protected function init(TransportInterface $transport, $sql) + { + $this->sql = $sql; + $this->transport = $transport; + + } + + /** + * @param array $bindings + */ + public function bindParams(array $bindings) + { + foreach ($bindings as $column => $value) { + $this->bindParam($column, $value); + } + } + + /** + * @param string $column + * @param mixed $value + */ + public function bindParam($column, $value) + { + $this->bindings[$column] = $value; + } + + /** + * Устанавливает формат вывода для SELECT/INSERT запроса + * + * @return string + */ + protected function prepareQueryFormat() + { + + if (null !== static::$format) { + $this->sql = $this->sql . ' FORMAT ' . static::$format; + } + + return $this->sql; + } + + /** + * Биндит параметры в sql + * @return string + */ + protected function prepareQueryBindings() + { + $keys = array(); + $values = $this->bindings; + + # build a regular expression for each parameter + foreach ($this->bindings as $key => $value) { + if (is_string($key)) { + $keys[] = '/:' . $key . '/'; + } else { + $keys[] = '/[?]/'; + } + + if (is_string($value)) + $values[$key] = "'" . $value . "'"; + + if (is_array($value)) + $values[$key] = "'" . implode("','", $value) . "'"; + + if (null === $value) + $values[$key] = ''; + } + $this->sql = preg_replace($keys, $values, $this->sql, 1, $count); + + return $this->sql; + } + + + /** + * @return string + */ + public function toSql() + { + $this->prepareQueryBindings(); + $this->prepareQueryFormat(); + return $this->sql; + } + + /** + * @return string + */ + public function __toString() + { + return $this->toSql(); + } +} \ No newline at end of file diff --git a/src/Query/QueryInterface.php b/src/Query/QueryInterface.php new file mode 100644 index 0000000..a7e5238 --- /dev/null +++ b/src/Query/QueryInterface.php @@ -0,0 +1,14 @@ +init($transport, $sql); + $this->bindParams($bindings); + } +} \ No newline at end of file diff --git a/src/Settings.php b/src/Settings.php new file mode 100644 index 0000000..5d5e2fa --- /dev/null +++ b/src/Settings.php @@ -0,0 +1,237 @@ +client = $client; + $this->setUpSettings($settings); + } + + /** + * @param string $name + * @return string + */ + public function __get($name) + { + if (!property_exists($this, $name)) { + throw new \InvalidArgumentException(sprintf('settings with name %s not exists', $name)); + } + + return $this->client->query('SELECT value FROM system.settings WHERE name = :name') + ->bindValue('name', $name) + ->fetchColumn(); + } + + public function __set($name, $value) + { + if (!property_exists($this, $name)) { + throw new \InvalidArgumentException(sprintf('settings with name %s not exists', $name)); + } + + $this->{$name} = $value; + return $this->client->execute('SET :name = :value'); + } + + public function __isset($name) + { + + } + + private function setUpSettings($settings) + { + foreach ($settings as $name => $value) { + $this->__set($name, $value); + } + } +} \ No newline at end of file diff --git a/src/Statement.php b/src/Statement.php new file mode 100644 index 0000000..fc33f40 --- /dev/null +++ b/src/Statement.php @@ -0,0 +1,209 @@ +transport = $transport; + $this->query = $query; + $this->prepareJsonResponse($data); + + } + + /** + * @param $data + * + * @return Statement + */ + protected function prepareJsonResponse($data) + { + $this->rawResult = $data; + + if (empty($data)) { + return $this; + } + + $this->result = json_decode($data); + foreach (self::JSON_RESPONSE_POSSIBLE_KEYS as $possibleKey) { + if (property_exists($this->result, $possibleKey)) { + $this->{$possibleKey} = $this->result->{$possibleKey}; + } + } + + return $this; + + } + + + /** + * @return array + */ + public function fetchAll() + { + return $this->data; + } + + /** + * @return \stdClass + */ + public function fetchOne() + { + return current($this->data); + } + + /** + * @param $name + * @return mixed + */ + public function fetchColumn($name) + { + $current = $this->fetchOne(); + + return $current->{$name}; + } + + /** + * @return int + */ + public function rowsCount() + { + return $this->rows; + } + + + + /** + * @return mixed + */ + public function getRawResult() + { + return $this->rawResult; + } + + /** + * @return \stdClass + */ + public function getResult() + { + return $this->result; + } + + /** + * @return mixed + */ + public function getRowsBeforeLimitAtLeast() + { + return $this->rows_before_limit_at_least; + } + + + /** + * @return array + */ + public function getMeta() + { + return $this->meta; + } + + /** + * @param string $column + * @return \stdClass + */ + public function getColumnMeta($column) + { + $meta = $this->getMeta(); + + return array_reduce($meta, function ($carry, $item) use ($column) { + if ($item->name === $column) { + $carry = $item; + } + + return $carry; + }); + } + + /** + * @return mixed + */ + public function getExtremes() + { + return $this->extremes; + } + + /** + * @return mixed + */ + public function getTotals() + { + return $this->totals; + } + +} \ No newline at end of file diff --git a/src/System.php b/src/System.php new file mode 100644 index 0000000..3189435 --- /dev/null +++ b/src/System.php @@ -0,0 +1,199 @@ +client = $client; + $this->settings = new Settings($client, $settings); + } + + /** + * Содержит информацию о кусках таблиц семейства MergeTree. + * @param int $limit + * @return array + */ + public function numbers($limit = 10) + { + $sql = 'SELECT number FROM system.numbers LIMIT ' . $limit; + $result = $this->client->select($sql); + + return $result->fetchAll(); + } + + /** + * Таблица содержит столбцы database, name, engine типа String. + * + * @return array + */ + public function tables($table = null) + { + $sql = 'SELECT * FROM system.tables'; + + if (null !== $table) { + $sql .= ' WHERE name=:name'; + } + + return $this->client->select($sql, ['name'=>$table]); + + } + + /** + * Таблица содержит один столбец name типа String - имя базы данных. + * Для каждой базы данных, о которой знает сервер, будет присутствовать соответствующая запись в таблице. + * + * @return array + */ + public function databases() + { + $sql = 'SHOW DATABASES'; + $result = $this->client->select($sql); + + return $result->fetchAll(); + } + + /** + * @return array + */ + public function processes() + { + $sql = 'SHOW PROCESSLIST'; + $result = $this->client->select($sql); + + return $result->fetchAll(); + } + + /** + * Содержит информацию о количестве произошедших в системе событий, для профилирования и мониторинга. + * Пример: количество обработанных запросов типа SELECT. + * Столбцы: event String - имя события, value UInt64 - количество. + * + * @return array + */ + public function events() + { + $sql = 'SELECT * FROM system.events'; + $result = $this->client->select($sql); + + return $result->fetchAll(); + } + + /** + * информация о доступных в конфигурационном файле кластерах и серверах, которые в них входят. + * + * @return Statement + */ + public function clusters() + { + $sql = 'SELECT * FROM system.clusters'; + $result = $this->client->select($sql); + + return $result; + } + + /** + * Содержит информацию о столбцах всех таблиц. + * + * @param null|string $table + * @return Statement + */ + public function columns($table = null) + { + $sql = 'SELECT * FROM system.columns'; + + if (null !== $table) { + $sql .= ' WHERE table=:table'; + } + + $result = $this->client->select($sql, ['table'=>$table]); + + return $result; + } + + /** + * информация о внешних словарях. + * @return array + */ + public function dictionaries() + { + $sql = 'SELECT * FROM system.dictionaries'; + $result = $this->client->select($sql); + + return $result->fetchAll(); + } + + /** + * Содержит информацию об обычных и агрегатных функциях. + * @return array + */ + public function functions() + { + $sql = 'SELECT * FROM system.functions'; + $result = $this->client->select($sql); + + return $result->fetchAll(); + } + + /** + * Содержит информацию о производящихся прямо сейчас слияниях для таблиц семейства MergeTree. + * @return array + */ + public function merges() + { + $sql = 'SELECT * FROM system.merges'; + $result = $this->client->select($sql); + + return $result->fetchAll(); + } + + /** + * Содержит информацию о кусках таблиц семейства MergeTree. + * @return array + */ + public function parts() + { + $sql = 'SELECT * FROM system.parts'; + $result = $this->client->select($sql); + + return $result->fetchAll(); + } + + /** + * Содержит информацию и статус для реплицируемых таблиц, расположенных на локальном сервере. + * @return array + */ + public function replicas($table) + { + $sql = 'SELECT * FROM system.replicas WHERE table=' . $table; + $result = $this->client->select($sql); + + return $result->fetchAll(); + } + + /** + * @return Settings + */ + public function settings() + { + return $this->settings; + } + + /** + * @return array + */ + public function zookeeper($path) + { + $sql = 'SELECT * FROM system.zookeeper WHERE $path = ' . $path; + $result = $this->client->select($sql); + + return $result->fetchAll(); + } + + + +} \ No newline at end of file diff --git a/src/Transport/Http.php b/src/Transport/Http.php new file mode 100644 index 0000000..c452bb5 --- /dev/null +++ b/src/Transport/Http.php @@ -0,0 +1,177 @@ +host = $host; + + if (null !== $port) + $this->port = $port; + + if(null !== $username) + $this->username = $username; + + if(null !== $password) + $this->password = $password; + + + if (array_key_exists('timeout', $requestOptions)) { + $this->timeout = $requestOptions['timeout']; + } + + $this->connect(); + } + + /** + * + */ + protected function connect() + { + $handler = new CurlHandler(); + $stack = HandlerStack::create($handler); + + $httpClientSettings = [ + 'base_uri' => $this->host . ':' . $this->port, + 'timeout' => $this->timeout, + 'handler' => $stack, + ]; + + if (null !== $this->username) { + $httpClientSettings['auth'] = [$this->username, $this->password]; + } + + $this->httpClient = new Client($httpClientSettings); + } + + + /** + * @param string $sql + * + * @param array $bindings + * @return Statement + * @throws \RuntimeException + */ + public function select($sql, array $bindings = []) + { + $query = new SelectQuery($this, $sql, $bindings); + + $response = $this->httpClient->request('GET', null, [ + 'query' => $this->prepareQueryGetRequest($query), + ]); + + $data = $response->getBody()->getContents(); + + return new Statement($data, $query, $this); + } + + + /** + * @param string $table + * @param array $values + * @param array $columns + * + * @return Statement + * @throws \RuntimeException + * + */ + public function insert($table, array $columns = [], array $values) + { + $query = new InsertQuery($this, $table, $columns, $values); + + $response = $this->httpClient->request('POST', null, [ + 'body' => $query->toSql(), + ]); + + $data = $response->getBody()->getContents(); + + return new Statement($data, $query, $this); + } + + /** + * @param $sql + * @param array $bindings + * + * @return Statement + * @throws \RuntimeException + */ + public function execute($sql, $bindings = []) + { + $query = new ExecuteQuery($this, $sql, $bindings); + + $response = $this->httpClient->request('POST', null, [ + 'body' => $query->toSql(), + ]); + + $data = $response->getBody()->getContents(); + + return new Statement($data, $query, $this); + } + + + /** + * @param Query $query + * + * @return array + * + */ + protected function prepareQueryGetRequest(Query $query) + { + return ['query' => $query->toSql()]; + } + +} diff --git a/src/Transport/TransportInterface.php b/src/Transport/TransportInterface.php new file mode 100644 index 0000000..8e1f66e --- /dev/null +++ b/src/Transport/TransportInterface.php @@ -0,0 +1,41 @@ +client = new \ClickHouse\Client('http://127.0.0.1', 8123); + + + $this->client->execute( + /** @lang SQL */ + "CREATE TABLE IF NOT EXISTS " . $this->tablename . " ( + RowId UInt32, + RowDate Date, + RowUInt8 UInt8, + RowInt16 Int16, + RowFloat32 Float32, + RowString String, + RowFixedString FixedString(20), + RowDateTime DateTime, + RowEnum8 Enum8('hello' = 1, 'world' = 2), + RowStringArray Array(String) + ) ENGINE = MergeTree(RowDate, (RowId, RowDate), 8124);" + ); + + } + + public function tearDown() + { + $this->client->execute('DROP TABLE IF EXISTS ' . $this->tablename); + } + + /** + * Заполняет тестовую таблицу, фейковыми данными + * @param int $count + */ + public function fixtures($count = 1000) + { + + } + + /** + * + */ + public function testPing() + { + $result = $this->client->ping(); + + $this->assertTrue($result); + + } + + public function testFetchAll() + { + $result = $this->client->select('SELECT number FROM system.numbers LIMIT 10'); + $data = $result->fetchAll(); + + $this->assertCount(10, $data); + + } + + public function testFetchWithBindings() + { + $result = $this->client->select('SELECT number FROM system.numbers WHERE number = :number LIMIT 1', ['number' => 100]); + $first = $result->fetchOne(); + + $this->assertEquals(100, $first->number); + + } + + public function testFetchOne() + { + $result = $this->client->select('SELECT number FROM system.numbers LIMIT 1'); + $first = $result->fetchOne(); + + $this->assertInstanceOf(\stdClass::class, $first); + $this->assertEquals(0, $first->number); + } + + public function testFetchColumn() + { + $result = $this->client->select('SELECT number FROM system.numbers LIMIT 1'); + $number = $result->fetchColumn('number'); + + $this->assertTrue(is_numeric($number)); + $this->assertEquals(0, $number); + } + + + public function testCreateDropTable() + { + + $tablename = 'test_create'; + $this->client->execute( + 'CREATE TABLE ' . $tablename . ' (abc UInt8) ENGINE = Memory;' + ); + + $st = $this->client->system()->columns($tablename); + $column = $st->fetchOne(); + + $this->assertEquals('abc', $column->name); + $this->assertEquals('uint8', strtolower($column->type)); + + + $this->client->execute( + 'DROP TABLE ' . $tablename . ';' + ); + } + + /** + * + */ + public function testInsertFormatValues() + { + $faker = Faker\Factory::create(); + $columns = ['RowId', 'RowDate', 'RowString']; + $data = [ + [$id1 = $faker->randomDigitNotNull, $date1 = $faker->date, $string1 = $faker->word], + [$id2 = $faker->randomDigitNotNull, $date2 = $faker->date, $string2 = $faker->word], + ]; + $this->client->insert($this->tablename, $columns, $data); + + $statement = $this->client->select('SELECT * FROM '.$this->tablename); + + $this->assertEquals(2, $statement->rowsCount()); + + $all = $statement->fetchAll(); + $first = current($all); + $this->assertEquals($id1, $first->RowId); + + $last = end($all); + $this->assertEquals($id2, $last->RowId); + + + } + + + public function insertBatch() + { + // $this->client->insert(); + } + + +} \ No newline at end of file From ff399083ea9e0b1ccfa193bfb265ae85d09dd271 Mon Sep 17 00:00:00 2001 From: Andrew Oblikov Date: Wed, 22 Aug 2018 18:36:43 +0300 Subject: [PATCH 2/3] Merge branch 'master' of https://github.com/andrewrbe/clickhouse-php-client # Conflicts: # src/Query/Grammar.php # src/Query/InsertQuery.php --- src/Query/Grammar.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Query/Grammar.php b/src/Query/Grammar.php index bd53094..2bc6a9e 100644 --- a/src/Query/Grammar.php +++ b/src/Query/Grammar.php @@ -30,13 +30,13 @@ public function getDateTimeFormat() */ public function quote($value) { - if (is_string($value)) + if (is_string($value)) { return "'" . addslashes($value) . "'"; + } - - if (is_array($value)) + if (is_array($value)) { return json_encode($value); - + } if (null === $value) return ''; From c4b1ae44ee9ceffe1e744863f50ce06c69821fb1 Mon Sep 17 00:00:00 2001 From: Andrew Oblikov Date: Sat, 31 Aug 2019 19:12:50 +0300 Subject: [PATCH 3/3] Fixed array of integers binding --- src/Query/Query.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Query/Query.php b/src/Query/Query.php index 3b023b7..0ea5e6a 100644 --- a/src/Query/Query.php +++ b/src/Query/Query.php @@ -36,7 +36,7 @@ public function __construct() { $this->grammar = new Grammar(); } - + /** * @param TransportInterface $transport * @param string $sql @@ -102,8 +102,15 @@ protected function prepareQueryBindings() if (is_string($value)) $values[$key] = "'" . $value . "'"; - if (is_array($value)) - $values[$key] = "'" . implode("','", $value) . "'"; + if (is_array($value)) { + $values[$key] = []; + foreach ($value as $v) { + $values[$key][] = is_numeric($v) ? $v : "'{$v}'"; + } + $values[$key] = implode(',', $values[$key]); + } + + if (null === $value) $values[$key] = '';