From 353a2e740039a966b7a2d6faffce5a7d84fa7660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Oct 2023 11:18:22 +0200 Subject: [PATCH 01/32] Implement DB proxy --- .env | 2 + .github/workflows/codeql-analysis.yml | 16 + .github/workflows/linter.yml | 16 + .gitignore | 3 + .gitpod.yml | 10 + Dockerfile | 78 + _build.txt | 2 + app/Validator/Assoc.php | 36 + app/endpoints.php | 493 +++++ app/http.php | 200 ++ composer.json | 40 + composer.lock | 2513 +++++++++++++++++++++++++ docker-compose.yml | 29 + phpstan.neon | 3 + pint.json | 3 + psalm.xml | 15 + 16 files changed, 3459 insertions(+) create mode 100644 .env create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/linter.yml create mode 100644 .gitignore create mode 100644 .gitpod.yml create mode 100644 Dockerfile create mode 100644 _build.txt create mode 100644 app/Validator/Assoc.php create mode 100644 app/endpoints.php create mode 100644 app/http.php create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 docker-compose.yml create mode 100644 phpstan.neon create mode 100644 pint.json create mode 100644 psalm.xml diff --git a/.env b/.env new file mode 100644 index 0000000..37b985d --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +UTOPIA_DATABASE_PROXY_SECRET=proxy-secret-key +UTOPIA_DATABASE_PROXY_SECRET_CONNECTIONS=default=mariadb://root:password@mariadb:3306/appwrite \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..3253e2c --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,16 @@ +name: "CodeQL" + +on: [pull_request] +jobs: + lint: + name: CodeQL + runs-on: ubuntu-latest + + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Run CodeQL + run: | + docker run --rm -v $PWD:/app composer sh -c \ + "composer install --profile --ignore-platform-reqs && composer check" \ No newline at end of file diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000..28f4c6a --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,16 @@ +name: "Linter" + +on: [pull_request] +jobs: + lint: + name: Linter + runs-on: ubuntu-latest + + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Run Linter + run: | + docker run --rm -v $PWD:/app composer sh -c \ + "composer install --profile --ignore-platform-reqs && composer lint" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..921bd61 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/vendor/ +/.idea/ +.phpunit.result.cache \ No newline at end of file diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000..96483d7 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,10 @@ +tasks: + - name: open-runtimes/proxy + init: | + docker compose pull + docker compose build + composer install --ignore-platform-reqs +vscode: + extensions: + - ms-azuretools.vscode-docker + - zobo.php-intellisense \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..15cbf2b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,78 @@ +# Install PHP libraries +FROM composer:2.0 as composer + +WORKDIR /usr/local/src/ + +COPY composer.lock /usr/local/src/ +COPY composer.json /usr/local/src/ + +RUN composer install --ignore-platform-reqs --optimize-autoloader \ + --no-plugins --no-scripts --prefer-dist + +# Prepare generic compiler +FROM php:8.0.18-cli-alpine3.15 as compile + +ENV PHP_SWOOLE_VERSION=v4.8.10 + +RUN \ + apk add --no-cache --virtual .deps \ + make \ + automake \ + autoconf \ + gcc \ + g++ \ + git \ + openssl-dev + +RUN docker-php-ext-install sockets + +# Compile Swoole +FROM compile AS swoole + +RUN \ + git clone --depth 1 --branch $PHP_SWOOLE_VERSION https://github.com/swoole/swoole-src.git && \ + cd swoole-src && \ + phpize && \ + ./configure --enable-sockets --enable-http2 --enable-openssl && \ + make && make install && \ + cd .. + +# Proxy +FROM php:8.0.18-cli-alpine3.15 as final + +ARG UTOPIA_DATABASE_PROXY_VERSION +ENV UTOPIA_DATABASE_PROXY_VERSION=$UTOPIA_DATABASE_PROXY_VERSION + +LABEL maintainer="team@appwrite.io" + +RUN \ + apk update \ + && apk add --no-cache --virtual .deps \ + make \ + automake \ + autoconf \ + gcc \ + g++ \ + curl-dev \ + && apk add --no-cache \ + libstdc++ \ + && docker-php-ext-install sockets pdo_mysql \ + && apk del .deps \ + && rm -rf /var/cache/apk/* + +WORKDIR /usr/local/ + +# Source code +COPY ./app /usr/local/app + +# Extensions and libraries +COPY --from=composer /usr/local/src/vendor /usr/local/vendor +COPY --from=swoole /usr/local/lib/php/extensions/no-debug-non-zts-20200930/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/ + +COPY ./vendor/utopia-php/database/src/Database/Adapter/MariaDB.php /usr/local/vendor/utopia-php/database/src/Database/Adapter/MariaDB.php + +RUN echo extension=swoole.so >> /usr/local/etc/php/conf.d/swoole.ini + +EXPOSE 80 + +CMD [ "php", "app/http.php" ] \ No newline at end of file diff --git a/_build.txt b/_build.txt new file mode 100644 index 0000000..04412d8 --- /dev/null +++ b/_build.txt @@ -0,0 +1,2 @@ +-- TODO: Convert this to real release process +docker build -t utopia-php/database-proxy:0.1.0 . \ No newline at end of file diff --git a/app/Validator/Assoc.php b/app/Validator/Assoc.php new file mode 100644 index 0000000..d763ef7 --- /dev/null +++ b/app/Validator/Assoc.php @@ -0,0 +1,36 @@ + MAX_STRING_SIZE) { + return false; + } + + return \array_keys($value) !== \range(0, \count($value) - 1); + } +} diff --git a/app/endpoints.php b/app/endpoints.php new file mode 100644 index 0000000..4d6ea27 --- /dev/null +++ b/app/endpoints.php @@ -0,0 +1,493 @@ +groups(['api']) + ->inject('adapter') + ->inject('response') + ->action(function (Adapter $adapter, Response $response) { + $output = $adapter->ping(); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/exists') + ->groups(['api']) + ->param('database', '', new Text(MAX_STRING_SIZE, 0)) + ->param('collection', null, new Text(MAX_STRING_SIZE, 0), '', true) + ->inject('adapter') + ->inject('response') + ->action(function (string $database, ?string $collection, Adapter $adapter, Response $response) { + $output = $adapter->exists($database, $collection); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/create') + ->groups(['api']) + ->param('name', '', new Text(MAX_STRING_SIZE, 0)) + ->inject('adapter') + ->inject('response') + ->action(function (string $name, Adapter $adapter, Response $response) { + $output = $adapter->create($name); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/delete') + ->groups(['api']) + ->param('name', '', new Text(MAX_STRING_SIZE, 0)) + ->inject('adapter') + ->inject('response') + ->action(function (string $name, Adapter $adapter, Response $response) { + $output = $adapter->delete($name); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/createCollection') + ->groups(['api']) + ->param('name', '', new Text(MAX_STRING_SIZE, 0)) + ->param('attributes', [], new ArrayList(new Assoc(), MAX_ARRAY_SIZE), '', true) + ->param('indexes', [], new ArrayList(new Assoc(), MAX_ARRAY_SIZE), '', true) + ->inject('adapter') + ->inject('response') + ->action(function (string $name, array $attributes, array $indexes, Adapter $adapter, Response $response) { + foreach ($attributes as &$attribute) { + $attribute = new Document($attribute); + } + + foreach ($indexes as &$index) { + $index = new Document($index); + } + + $output = $adapter->createCollection($name, $attributes, $indexes); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/deleteCollection') + ->groups(['api']) + ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->inject('adapter') + ->inject('response') + ->action(function (string $id, Adapter $adapter, Response $response) { + $output = $adapter->deleteCollection($id); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/createAttribute') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('type', '', new Text(MAX_STRING_SIZE, 0)) + ->param('size', '', new Integer()) + ->param('signed', true, new Boolean(), '', true) + ->param('array', false, new Boolean(), '', true) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $id, string $type, int $size, bool $signed, bool $array, Adapter $adapter, Response $response) { + $output = $adapter->createAttribute($collection, $id, $type, $size, $signed, $array); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/updateAttribute') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('type', '', new Text(MAX_STRING_SIZE, 0)) + ->param('size', '', new Integer()) + ->param('signed', true, new Boolean(), '', true) + ->param('array', false, new Boolean(), '', true) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $id, string $type, int $size, bool $signed, bool $array, Adapter $adapter, Response $response) { + $output = $adapter->updateAttribute($collection, $id, $type, $size, $signed, $array); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/deleteAttribute') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $id, Adapter $adapter, Response $response) { + $output = $adapter->deleteAttribute($collection, $id); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/renameAttribute') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('old', '', new Text(MAX_STRING_SIZE, 0)) + ->param('new', '', new Text(MAX_STRING_SIZE, 0)) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $old, string $new, Adapter $adapter, Response $response) { + $output = $adapter->renameAttribute($collection, $old, $new); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/createIndex') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('type', '', new Text(MAX_STRING_SIZE, 0)) + ->param('attributes', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE)) + ->param('lengths', [], new ArrayList(new Integer(), MAX_ARRAY_SIZE)) + ->param('orders', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE)) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $id, string $type, array $attributes, array $lengths, array $orders, Adapter $adapter, Response $response) { + $output = $adapter->createIndex($collection, $id, $type, $attributes, $lengths, $orders); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/renameIndex') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('old', '', new Text(MAX_STRING_SIZE, 0)) + ->param('new', '', new Text(MAX_STRING_SIZE, 0)) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $old, string $new, Adapter $adapter, Response $response) { + $output = $adapter->renameIndex($collection, $old, $new); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/deleteIndex') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $id, Adapter $adapter, Response $response) { + $output = $adapter->deleteIndex($collection, $id); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/getSizeOfCollection') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, Adapter $adapter, Response $response) { + $output = $adapter->getSizeOfCollection($collection); + + $response->json([ + 'output' => $output + ]); + }); + + +Http::post('/v1/queries/getCountOfAttributes') + ->groups(['api']) + ->param('collection', '', new Assoc()) + ->inject('adapter') + ->inject('response') + ->action(function (array $collection, Adapter $adapter, Response $response) { + $collection = new Document($collection); + + $output = $adapter->getCountOfAttributes($collection); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/getCountOfIndexes') + ->groups(['api']) + ->param('collection', '', new Assoc()) + ->inject('adapter') + ->inject('response') + ->action(function (array $collection, Adapter $adapter, Response $response) { + $collection = new Document($collection); + + $output = $adapter->getCountOfIndexes($collection); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/getAttributeWidth') + ->groups(['api']) + ->param('collection', '', new Assoc()) + ->inject('adapter') + ->inject('response') + ->action(function (array $collection, Adapter $adapter, Response $response) { + $collection = new Document($collection); + + $output = $adapter->getAttributeWidth($collection); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/createDocument') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('document', '', new Assoc()) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, array $document, Adapter $adapter, Response $response) { + $document = new Document($document); + + $output = $adapter->createDocument($collection, $document); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/updateDocument') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('document', '', new Assoc()) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, array $document, Adapter $adapter, Response $response) { + $document = new Document($document); + + $output = $adapter->updateDocument($collection, $document); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/deleteDocument') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $id, Adapter $adapter, Response $response) { + $output = $adapter->deleteDocument($collection, $id); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/getDocument') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('queries', [], new ArrayList(new Assoc(), MAX_ARRAY_SIZE), '', true) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $id, array $queries, Adapter $adapter, Response $response) { + foreach ($queries as &$query) { + $query = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); + } + + $output = $adapter->getDocument($collection, $id, $queries); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/find') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('queries', [], new ArrayList(new Assoc(), MAX_ARRAY_SIZE), '', true) + ->param('limit', 25, new Integer(), '', true) + ->param('offset', null, new Integer(), '', true) + ->param('orderAttributes', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) + ->param('orderTypes', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) + ->param('cursor', [], new Assoc(), '', true) + ->param('cursorDirection', Database::CURSOR_AFTER, new Text(MAX_STRING_SIZE, 0), '', true) + ->param('timeout', null, new Integer(), '', true) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, array $queries, ?int $limit, ?int $offset, array $orderAttributes, array $orderTypes, array $cursor, string $cursorDirection, ?int $timeout, Adapter $adapter, Response $response) { + foreach ($queries as &$query) { + $query = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); + } + + \var_dump($collection); + \var_dump($queries); + \var_dump($limit); + \var_dump($offset); + \var_dump('---'); + + $output = $adapter->find($collection, $queries, $limit, $offset, $orderAttributes, $orderTypes, $cursor, $cursorDirection, $timeout); + + \var_dump($output); + \var_dump('==='); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/sum') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) + ->param('queries', [], new ArrayList(new Assoc(), MAX_ARRAY_SIZE), '', true) + ->param('max', null, new Integer(), '', true) + ->param('timeout', null, new Integer(), '', true) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $attribute, array $queries, ?int $max, ?int $timeout, Adapter $adapter, Response $response) { + foreach ($queries as &$query) { + $query = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); + } + + $output = $adapter->sum($collection, $attribute, $queries, $max, $timeout); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/count') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('queries', [], new ArrayList(new Assoc(), MAX_ARRAY_SIZE), '', true) + ->param('max', null, new Integer(), '', true) + ->param('timeout', null, new Integer(), '', true) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, array $queries, ?int $max, ?int $timeout, Adapter $adapter, Response $response) { + foreach ($queries as &$query) { + $query = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); + } + + $output = $adapter->count($collection, $queries, $max, $timeout); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/increaseDocumentAttribute') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) + ->param('value', null, new FloatValidator(), '', true) + ->param('min', null, new FloatValidator(), '', true) + ->param('max', null, new FloatValidator(), '', true) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $id, string $attribute, float $value, ?float $min, ?float $max, Adapter $adapter, Response $response) { + $output = $adapter->increaseDocumentAttribute($collection, $id, $attribute, $value, $min, $max); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/createRelationship') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('relatedCollection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('type', '', new Text(MAX_STRING_SIZE, 0)) + ->param('twoWay', false, new Boolean(), '', true) + ->param('id', '', new Text(MAX_STRING_SIZE, 0), '', true) + ->param('twoWayKey', '', new Text(MAX_STRING_SIZE, 0), '', true) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $relatedCollection, string $type, bool $twoWay, string $id, string $twoWayKey, Adapter $adapter, Response $response) { + $output = $adapter->createRelationship($collection, $relatedCollection, $type, $twoWay, $id, $twoWayKey); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/updateRelationship') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('relatedCollection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('type', '', new Text(MAX_STRING_SIZE, 0)) + ->param('twoWay', false, new Boolean()) + ->param('key', '', new Text(MAX_STRING_SIZE, 0)) + ->param('twoWayKey', '', new Text(MAX_STRING_SIZE, 0)) + ->param('newKey', null, new Text(MAX_STRING_SIZE, 0), '', true) + ->param('newTwoWayKey', null, new Text(MAX_STRING_SIZE, 0), '', true) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $relatedCollection, string $type, bool $twoWay, string $key, string $twoWayKey, string $newKey, string $newTwoWayKey, Adapter $adapter, Response $response) { + $output = $adapter->updateRelationship($collection, $relatedCollection, $type, $twoWay, $key, $twoWayKey, $newKey, $newTwoWayKey); + + $response->json([ + 'output' => $output + ]); + }); + +Http::post('/v1/queries/deleteRelationship') + ->groups(['api']) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('relatedCollection', '', new Text(MAX_STRING_SIZE, 0)) + ->param('type', '', new Text(MAX_STRING_SIZE, 0)) + ->param('twoWay', false, new Boolean()) + ->param('key', '', new Text(MAX_STRING_SIZE, 0)) + ->param('twoWayKey', '', new Text(MAX_STRING_SIZE, 0)) + ->param('side', '', new Text(MAX_STRING_SIZE, 0)) + ->inject('adapter') + ->inject('response') + ->action(function (string $collection, string $relatedCollection, string $type, bool $twoWay, string $key, string $twoWayKey, string $side, Adapter $adapter, Response $response) { + $output = $adapter->deleteRelationship($collection, $relatedCollection, $type, $twoWay, $key, $twoWayKey, $side); + + $response->json([ + 'output' => $output + ]); + }); diff --git a/app/http.php b/app/http.php new file mode 100644 index 0000000..91fe5a2 --- /dev/null +++ b/app/http.php @@ -0,0 +1,200 @@ +set('adapters', function () { + $dsns = \explode(',', Http::getEnv('UTOPIA_DATABASE_PROXY_SECRET_CONNECTIONS', '') ?? ''); + + $adapters = []; + + foreach ($dsns as $dsnPair) { + [$dsnName, $dsnString] = explode('=', $dsnPair); + $dsn = new DSN($dsnString); + $dsnHost = $dsn->getHost(); + $dsnPort = $dsn->getPort(); + $dsnUser = $dsn->getUser(); + $dsnPass = $dsn->getPassword(); + $dsnScheme = $dsn->getScheme(); + $dsnDatabase = $dsn->getPath() ?? ''; + + // TODO: Introduce pools with ?pool_size=64 + + switch ($dsnScheme) { + case 'mariadb': + $adapters[$dsnName] = function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { + $pdo = new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, array( + PDO::ATTR_TIMEOUT => 15, // Seconds + PDO::ATTR_PERSISTENT => false, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + // PDO::ATTR_ERRMODE => Http::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed + PDO::ATTR_EMULATE_PREPARES => true, + PDO::ATTR_STRINGIFY_FETCHES => true + )); + $adapter = new MariaDB($pdo); + $adapter->setDefaultDatabase($dsnDatabase); + return $adapter; + }; + break; + }; + } + + return $adapters; +}); + +$http = new Server("0.0.0.0", Http::getEnv('UTOPIA_DATABASE_PROXY_PORT', '80')); + +$payloadSize = 20 * (1024 * 1024); // 20MB + +$http + ->setConfig([ + 'open_http2_protocol' => true, + 'http_compression' => true, + 'http_compression_level' => 6, + 'package_max_length' => $payloadSize, + 'buffer_output_size' => $payloadSize, + ]); + +Http::onStart() + ->action(function () { + Console::success("HTTP server started."); + }); + +Http::setResource('registry', fn () => $registry); + +Http::setResource('adapters', fn (Registry $registry) => $registry->get('adapters'), ['registry']); + +Http::setResource('adapter', function (Request $request, array $adapters) { + $database = $request->getHeader('x-utopia-database', ''); + $namespace = $request->getHeader('x-utopia-namespace', ''); + $timeout = $request->getHeader('x-utopia-timeout', ''); + $defaultDatabase = $request->getHeader('x-utopia-default-database', ''); + $roles = $request->getHeader('x-utopia-auth-roles', ''); + $status = $request->getHeader('x-utopia-auth-status', ''); + $statusDefault = $request->getHeader('x-utopia-auth-status-default', ''); + + if (empty($database)) { + throw new Exception('Incorrect database in x-utopia-database header.', 400); + } + + $adapter = $adapters[$database] ?? null; + + if (empty($adapter)) { + throw new Exception('Incorrect database in x-utopia-database header.', 400); + } + + $resource = $adapter(); + $resource->setNamespace($namespace); + + if (!empty($timeout)) { + $resource->setTimeout($timeout); + } else { + $resource->clearTimeout(); + } + + if (!empty($defaultDatabase)) { + $resource->setDefaultDatabase($defaultDatabase); + } else { + $resource->setDefaultDatabase(''); + } + + Authorization::cleanRoles(); + Authorization::setRole('any'); + foreach (\explode(',', $roles) as $role) { + Authorization::setRole($role); + } + + if (!empty($statusDefault)) { + if($statusDefault === 'true') { + Authorization::setDefaultStatus(true); + } else { + Authorization::setDefaultStatus(false); + } + } + + if (!empty($status)) { + if ($status === 'true') { + Authorization::enable(); + } else { + Authorization::disable(); + } + } + + return $resource; +}, ['request', 'adapters']); + +Http::init() + ->groups(['api']) + ->inject('request') + ->action(function (Request $request) { + $secret = Http::getEnv('UTOPIA_DATABASE_PROXY_SECRET', ''); + $header = $request->getHeader('x-utopia-secret', ''); + + if ($header !== $secret) { + throw new Exception('Incorrect secret in x-utopia-secret header.', 401); + } + }); + +Http::error() + ->inject('error') + ->inject('response') + ->action(function (Throwable $error, Response $response) { + // TODO: Log to Sentry + + switch ($error->getCode()) { + case 400: // Error allowed publicly + case 401: // Error allowed publicly + case 402: // Error allowed publicly + case 403: // Error allowed publicly + case 404: // Error allowed publicly + case 406: // Error allowed publicly + case 409: // Error allowed publicly + case 412: // Error allowed publicly + case 425: // Error allowed publicly + case 429: // Error allowed publicly + case 501: // Error allowed publicly + case 503: // Error allowed publicly + $code = $error->getCode(); + break; + default: + $code = 500; // All other errors get the generic 500 server error status code + } + + $output = [ + 'type' => \get_class($error), + 'message' => $error->getMessage(), + 'code' => $error->getCode(), + 'file' => $error->getFile(), + 'line' => $error->getLine(), + 'trace' => $error->getTrace(), + 'version' => Http::getEnv('UTOPIA_DATABASE_PROXY_VERSION', 'UNKNOWN') + ]; + + $response + ->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate') + ->addHeader('Expires', '0') + ->addHeader('Pragma', 'no-cache') + ->setStatusCode(\intval($code)); + + $response->json($output); + }); + +run(function () use ($http) { + $app = new Http($http, 'UTC'); + $app->start(); +}); diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..5a768b5 --- /dev/null +++ b/composer.json @@ -0,0 +1,40 @@ +{ + "name": "utopia/database-proxy", + "description": "HTTP proxy to manage Utopia Database connections.", + "type": "project", + "license": "MIT", + "autoload": { + "psr-4": { + "Utopia\\DatabaseProxy\\": "app" + } + }, + "scripts": { + "lint": "./vendor/bin/pint --preset psr12 --test", + "format": "./vendor/bin/pint --preset psr12", + "check": "./vendor/bin/phpstan analyse --level 8 -c phpstan.neon app", + "test": "./vendor/bin/phpunit --configuration phpunit.xml --debug" + }, + "require": { + "php": ">=8.0.0", + "ext-curl": "*", + "ext-json": "*", + "ext-swoole": "*" + }, + "require-dev": { + "swoole/ide-helper": "4.8.5", + "phpunit/phpunit": "^9.3", + "laravel/pint": "1.2.*", + "phpstan/phpstan": "1.8.*", + "utopia-php/framework": "dev-fix-v2-swoole-coroutines as 0.32.99", + "utopia-php/database": "dev-feat-framework-v2 as 0.44.99", + "utopia-php/cache": "0.8.*", + "utopia-php/cli": "0.16.*", + "utopia-php/registry": "0.6.*", + "utopia-php/dsn": "0.1.*" + }, + "config": { + "platform": { + "php": "8.0" + } + } +} \ No newline at end of file diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..04f6dd6 --- /dev/null +++ b/composer.lock @@ -0,0 +1,2513 @@ +{ + "_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#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "184f24da457f75e89e7f05b150b8802d", + "packages": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" + }, + "type": "library", + "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": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:23:10+00:00" + }, + { + "name": "jean85/pretty-package-versions", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0.0", + "php": "^7.1|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.17", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^0.12.66", + "phpunit/phpunit": "^7.5|^8.5|^9.4", + "vimeo/psalm": "^4.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A library to get pretty versions strings of installed dependencies", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5" + }, + "time": "2021-10-08T21:21:46+00:00" + }, + { + "name": "laravel/pint", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/pint.git", + "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pint/zipball/e60e2112ee779ce60f253695b273d1646a17d6f1", + "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.11.0", + "illuminate/view": "^9.32.0", + "laravel-zero/framework": "^9.2.0", + "mockery/mockery": "^1.5.1", + "nunomaduro/larastan": "^2.2.0", + "nunomaduro/termwind": "^1.14.0", + "pestphp/pest": "^1.22.1" + }, + "bin": [ + "builds/pint" + ], + "type": "project", + "autoload": { + "psr-4": { + "App\\": "app/", + "Database\\Seeders\\": "database/seeders/", + "Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "An opinionated code formatter for PHP.", + "homepage": "https://laravel.com", + "keywords": [ + "format", + "formatter", + "lint", + "linter", + "php" + ], + "support": { + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" + }, + "time": "2022-11-29T16:25:20+00:00" + }, + { + "name": "mongodb/mongodb", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/mongodb/mongo-php-library.git", + "reference": "b0bbd657f84219212487d01a8ffe93a789e1e488" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/b0bbd657f84219212487d01a8ffe93a789e1e488", + "reference": "b0bbd657f84219212487d01a8ffe93a789e1e488", + "shasum": "" + }, + "require": { + "ext-hash": "*", + "ext-json": "*", + "ext-mongodb": "^1.11.0", + "jean85/pretty-package-versions": "^1.2 || ^2.0.1", + "php": "^7.1 || ^8.0", + "symfony/polyfill-php80": "^1.19" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0", + "squizlabs/php_codesniffer": "^3.6", + "symfony/phpunit-bridge": "^5.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "MongoDB\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Andreas Braun", + "email": "andreas.braun@mongodb.com" + }, + { + "name": "Jeremy Mikola", + "email": "jmikola@gmail.com" + } + ], + "description": "MongoDB driver library", + "homepage": "https://jira.mongodb.org/browse/PHPLIB", + "keywords": [ + "database", + "driver", + "mongodb", + "persistence" + ], + "support": { + "issues": "https://github.com/mongodb/mongo-php-library/issues", + "source": "https://github.com/mongodb/mongo-php-library/tree/1.10.0" + }, + "time": "2021-10-20T22:22:37+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2023-03-08T13:26:56+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.17.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + }, + "time": "2023-08-13T19:53:39+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "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": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "1.8.11", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "46e223dd68a620da18855c23046ddb00940b4014" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/46e223dd68a620da18855c23046ddb00940b4014", + "reference": "46e223dd68a620da18855c23046ddb00940b4014", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/phpstan/issues", + "source": "https://github.com/phpstan/phpstan/tree/1.8.11" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2022-10-24T15:45:13+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.29", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.15", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-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 provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-09-19T04:57:46+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-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": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-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": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-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": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-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": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.13", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.28", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "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" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2023-09-19T05:39:22+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "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", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "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", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-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/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-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 for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-05-07T05:35:17+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-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" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T06:03:37+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bde739e7565280bda77be70044ac1047bc007e34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.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" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-08-02T09:26:13+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "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", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-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/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-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", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-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": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-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", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "swoole/ide-helper", + "version": "4.8.5", + "source": { + "type": "git", + "url": "https://github.com/swoole/ide-helper.git", + "reference": "d03c707d4dc803228e93b4884c72949c4d28e8b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swoole/ide-helper/zipball/d03c707d4dc803228e93b4884c72949c4d28e8b8", + "reference": "d03c707d4dc803228e93b4884c72949c4d28e8b8", + "shasum": "" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Team Swoole", + "email": "team@swoole.com" + } + ], + "description": "IDE help files for Swoole.", + "support": { + "issues": "https://github.com/swoole/ide-helper/issues", + "source": "https://github.com/swoole/ide-helper/tree/4.8.5" + }, + "funding": [ + { + "url": "https://gitee.com/swoole/swoole?donate=true", + "type": "custom" + }, + { + "url": "https://github.com/swoole", + "type": "github" + } + ], + "time": "2021-12-24T22:44:20+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-26T09:26:14+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" + }, + { + "name": "utopia-php/cache", + "version": "0.8.0", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/cache.git", + "reference": "212e66100a1f32e674fca5d9bc317cc998303089" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/cache/zipball/212e66100a1f32e674fca5d9bc317cc998303089", + "reference": "212e66100a1f32e674fca5d9bc317cc998303089", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-memcached": "*", + "ext-redis": "*", + "php": ">=8.0" + }, + "require-dev": { + "laravel/pint": "1.2.*", + "phpunit/phpunit": "^9.3", + "vimeo/psalm": "4.13.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Cache\\": "src/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A simple cache library to manage application cache storing, loading and purging", + "keywords": [ + "cache", + "framework", + "php", + "upf", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/cache/issues", + "source": "https://github.com/utopia-php/cache/tree/0.8.0" + }, + "time": "2022-10-16T16:48:09+00:00" + }, + { + "name": "utopia-php/cli", + "version": "0.16.0", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/cli.git", + "reference": "5b936638c90c86d1bae83d0dbe81fe14d12ff8ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/cli/zipball/5b936638c90c86d1bae83d0dbe81fe14d12ff8ff", + "reference": "5b936638c90c86d1bae83d0dbe81fe14d12ff8ff", + "shasum": "" + }, + "require": { + "php": ">=7.4", + "utopia-php/framework": "0.*.*" + }, + "require-dev": { + "laravel/pint": "1.2.*", + "phpunit/phpunit": "^9.3", + "squizlabs/php_codesniffer": "^3.6", + "vimeo/psalm": "4.0.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\CLI\\": "src/CLI" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A simple CLI library to manage command line applications", + "keywords": [ + "cli", + "command line", + "framework", + "php", + "upf", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/cli/issues", + "source": "https://github.com/utopia-php/cli/tree/0.16.0" + }, + "time": "2023-08-05T13:13:08+00:00" + }, + { + "name": "utopia-php/database", + "version": "dev-feat-framework-v2", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/database.git", + "reference": "1d4ab3dfafbe7a3adfd167e5e288c19634c223ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/database/zipball/1d4ab3dfafbe7a3adfd167e5e288c19634c223ce", + "reference": "1d4ab3dfafbe7a3adfd167e5e288c19634c223ce", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-pdo": "*", + "php": ">=8.0", + "utopia-php/cache": "0.8.*", + "utopia-php/framework": "dev-fix-v2-swoole-coroutines as 0.31.0", + "utopia-php/mongo": "0.3.*" + }, + "require-dev": { + "fakerphp/faker": "^1.14", + "laravel/pint": "1.4.*", + "pcov/clobber": "^2.0", + "phpstan/phpstan": "1.10.*", + "phpunit/phpunit": "^9.4", + "rregeer/phpunit-coverage-check": "^0.3.1", + "swoole/ide-helper": "4.8.0", + "utopia-php/cli": "^0.14.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Database\\": "src/Database" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A simple library to manage application persistence using multiple database adapters", + "keywords": [ + "database", + "framework", + "php", + "upf", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/database/issues", + "source": "https://github.com/utopia-php/database/tree/feat-framework-v2" + }, + "time": "2023-10-05T09:43:50+00:00" + }, + { + "name": "utopia-php/dsn", + "version": "0.1.0", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/dsn.git", + "reference": "17a5935eab1b89fb4b95600db50a1b6d5faa6cea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/dsn/zipball/17a5935eab1b89fb4b95600db50a1b6d5faa6cea", + "reference": "17a5935eab1b89fb4b95600db50a1b6d5faa6cea", + "shasum": "" + }, + "require": { + "php": ">=8.0" + }, + "require-dev": { + "laravel/pint": "1.2.*", + "phpunit/phpunit": "^9.3", + "squizlabs/php_codesniffer": "^3.6", + "vimeo/psalm": "4.0.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\DSN\\": "src/DSN" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A simple library for parsing and managing Data Source Names ( DSNs )", + "keywords": [ + "dsn", + "framework", + "php", + "upf", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/dsn/issues", + "source": "https://github.com/utopia-php/dsn/tree/0.1.0" + }, + "time": "2022-10-26T10:06:20+00:00" + }, + { + "name": "utopia-php/framework", + "version": "dev-fix-v2-swoole-coroutines", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/framework.git", + "reference": "c68f74e633edfdc71c42d175c0505427d00848b7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/c68f74e633edfdc71c42d175c0505427d00848b7", + "reference": "c68f74e633edfdc71c42d175c0505427d00848b7", + "shasum": "" + }, + "require": { + "ext-swoole": "*", + "php": ">=8.0" + }, + "require-dev": { + "laravel/pint": "^1.2", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.25", + "swoole/ide-helper": "4.8.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Http\\": "src/Http" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A simple, light and advanced PHP framework", + "keywords": [ + "framework", + "php", + "upf" + ], + "support": { + "issues": "https://github.com/utopia-php/framework/issues", + "source": "https://github.com/utopia-php/framework/tree/fix-v2-swoole-coroutines" + }, + "time": "2023-10-11T08:46:00+00:00" + }, + { + "name": "utopia-php/mongo", + "version": "0.3.1", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/mongo.git", + "reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/mongo/zipball/52326a9a43e2d27ff0c15c48ba746dacbe9a7aee", + "reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee", + "shasum": "" + }, + "require": { + "ext-mongodb": "*", + "mongodb/mongodb": "1.10.0", + "php": ">=8.0" + }, + "require-dev": { + "fakerphp/faker": "^1.14", + "laravel/pint": "1.2.*", + "phpstan/phpstan": "1.8.*", + "phpunit/phpunit": "^9.4", + "swoole/ide-helper": "4.8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Mongo\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eldad Fux", + "email": "eldad@appwrite.io" + }, + { + "name": "Wess", + "email": "wess@appwrite.io" + } + ], + "description": "A simple library to manage Mongo database", + "keywords": [ + "database", + "mongo", + "php", + "upf", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/mongo/issues", + "source": "https://github.com/utopia-php/mongo/tree/0.3.1" + }, + "time": "2023-09-01T17:25:28+00:00" + }, + { + "name": "utopia-php/registry", + "version": "0.6.0", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/registry.git", + "reference": "9c183312e48c926135085f34ac2e73dadb83e0c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/registry/zipball/9c183312e48c926135085f34ac2e73dadb83e0c8", + "reference": "9c183312e48c926135085f34ac2e73dadb83e0c8", + "shasum": "" + }, + "require": { + "php": ">=7.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "vimeo/psalm": "4.0.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Registry\\": "src/Registry" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eldad Fux", + "email": "eldad@appwrite.io" + } + ], + "description": "A simple dependency management library for PHP", + "keywords": [ + "dependency management", + "di", + "framework", + "php", + "upf", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/registry/issues", + "source": "https://github.com/utopia-php/registry/tree/0.6.0" + }, + "time": "2022-07-17T15:26:57+00:00" + } + ], + "aliases": [ + { + "package": "utopia-php/database", + "version": "dev-feat-framework-v2", + "alias": "0.44.99", + "alias_normalized": "0.44.99.0" + }, + { + "package": "utopia-php/framework", + "version": "dev-fix-v2-swoole-coroutines", + "alias": "0.32.99", + "alias_normalized": "0.32.99.0" + } + ], + "minimum-stability": "stable", + "stability-flags": { + "utopia-php/framework": 20, + "utopia-php/database": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=8.0.0", + "ext-curl": "*", + "ext-json": "*", + "ext-swoole": "*" + }, + "platform-dev": [], + "platform-overrides": { + "php": "8.0" + }, + "plugin-api-version": "2.3.0" +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3af1cc0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,29 @@ +version: '3.1' + +services: + tests: + container_name: tests + image: proxy-dev + build: + context: . + networks: + - database + volumes: + - ./app:/usr/local/app + ports: + - 8088:80 + environment: + - UTOPIA_DATABASE_PROXY_SECRET + - UTOPIA_DATABASE_PROXY_SECRET_CONNECTIONS + + mariadb: + image: mariadb:10.7 + container_name: utopia-mariadb + networks: + - database + environment: + - MYSQL_ROOT_PASSWORD=password + - MARIADB_DATABASE=appwrite + +networks: + database: \ No newline at end of file diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..69758b9 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,3 @@ +parameters: + scanDirectories: + - vendor/swoole/ide-helper \ No newline at end of file diff --git a/pint.json b/pint.json new file mode 100644 index 0000000..c781933 --- /dev/null +++ b/pint.json @@ -0,0 +1,3 @@ +{ + "preset": "psr12" +} \ No newline at end of file diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..b5d5891 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file From 2a8fb48bb2c2d635c29d0133bf081b41561fff05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Oct 2023 15:26:21 +0200 Subject: [PATCH 02/32] linter fix --- app/Validator/Assoc.php | 2 +- app/endpoints.php | 9 --------- app/http.php | 2 +- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/app/Validator/Assoc.php b/app/Validator/Assoc.php index d763ef7..255c8ae 100644 --- a/app/Validator/Assoc.php +++ b/app/Validator/Assoc.php @@ -25,7 +25,7 @@ public function isValid($value): bool } $jsonString = \json_encode($value); - $jsonStringSize = \strlen($jsonString); + $jsonStringSize = \strlen($jsonString ? $jsonString : ''); if ($jsonStringSize > MAX_STRING_SIZE) { return false; diff --git a/app/endpoints.php b/app/endpoints.php index 4d6ea27..85cc041 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -360,17 +360,8 @@ $query = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); } - \var_dump($collection); - \var_dump($queries); - \var_dump($limit); - \var_dump($offset); - \var_dump('---'); - $output = $adapter->find($collection, $queries, $limit, $offset, $orderAttributes, $orderTypes, $cursor, $cursorDirection, $timeout); - \var_dump($output); - \var_dump('==='); - $response->json([ 'output' => $output ]); diff --git a/app/http.php b/app/http.php index 91fe5a2..fe5c5c8 100644 --- a/app/http.php +++ b/app/http.php @@ -120,7 +120,7 @@ } if (!empty($statusDefault)) { - if($statusDefault === 'true') { + if ($statusDefault === 'true') { Authorization::setDefaultStatus(true); } else { Authorization::setDefaultStatus(false); From 1fb9ad23f885ffdaccbadc36c8150224066938b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Oct 2023 15:31:26 +0200 Subject: [PATCH 03/32] Remove leftover --- Dockerfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 15cbf2b..5b1bec7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -69,8 +69,6 @@ COPY ./app /usr/local/app COPY --from=composer /usr/local/src/vendor /usr/local/vendor COPY --from=swoole /usr/local/lib/php/extensions/no-debug-non-zts-20200930/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/ -COPY ./vendor/utopia-php/database/src/Database/Adapter/MariaDB.php /usr/local/vendor/utopia-php/database/src/Database/Adapter/MariaDB.php - RUN echo extension=swoole.so >> /usr/local/etc/php/conf.d/swoole.ini EXPOSE 80 From 767361d1000bb4e927905c57540a953a6c72da6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 17 Oct 2023 16:52:53 +0200 Subject: [PATCH 04/32] Add tests, address PR comments --- .env | 5 +- .github/workflows/release.yml | 41 + .github/workflows/tests.yml | 33 + .gitpod.yml | 10 - _build.txt | 2 - app/Validator/Assoc.php | 36 - app/endpoints.php | 35 +- app/http.php | 92 +- composer.json | 23 +- composer.lock | 2383 +++++++++++++++++---------------- docker-compose.yml | 5 + phpunit.xml | 16 + pint.json | 5 +- tests/ProxyTest.php | 177 +++ 14 files changed, 1635 insertions(+), 1228 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/tests.yml delete mode 100644 .gitpod.yml delete mode 100644 _build.txt delete mode 100644 app/Validator/Assoc.php create mode 100644 phpunit.xml create mode 100644 tests/ProxyTest.php diff --git a/.env b/.env index 37b985d..8de49d9 100644 --- a/.env +++ b/.env @@ -1,2 +1,5 @@ +UTOPIA_DATABASE_PROXY_ENV=development UTOPIA_DATABASE_PROXY_SECRET=proxy-secret-key -UTOPIA_DATABASE_PROXY_SECRET_CONNECTIONS=default=mariadb://root:password@mariadb:3306/appwrite \ No newline at end of file +UTOPIA_DATABASE_PROXY_SECRET_CONNECTIONS=default=mariadb://root:password@mariadb:3306/appwrite +UTOPIA_DATABASE_PROXY_LOGGING_PROVIDER= +UTOPIA_DATABASE_PROXY_LOGGING_CONFIG= \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..69cda76 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,41 @@ +name: "Release" + +on: + release: + types: [published] + +env: + IMAGE_NAME: utopia-php/database-proxy + TAG: ${{ github.event.release.tag_name }} + USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ env.USERNAME }} + password: ${{ env.PASSWORD }} + + - name: Build and push + uses: docker/build-push-action@v4 + with: + build-args: | + UTOPIA_DATABASE_PROXY_VERSION=${{ env.TAG }} + platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7 + context: . + push: true + tags: ${{ env.IMAGE_NAME }}:latest,${{ env.IMAGE_NAME }}:${{ env.TAG }} \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..2b780f0 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,33 @@ +name: "Tests" + +on: [pull_request] +jobs: + tests: + name: Tests + runs-on: ubuntu-latest + + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Start Test Stack + run: | + export COMPOSE_INTERACTIVE_NO_CLI + export DOCKER_BUILDKIT=1 + export COMPOSE_DOCKER_CLI_BUILD=1 + export BUILDKIT_PROGRESS=plain + docker pull composer:2.0 + docker compose build + docker compose up -d + sleep 60 + + - name: Doctor + run: | + docker compose logs + docker ps + docker network ls + + - name: Run Tests + run: | + docker run --rm -v $PWD:/app --network database-proxy_database -w /app phpswoole/swoole:4.8.12-php8.0-alpine sh -c \ + "composer install --profile --ignore-platform-reqs && composer test" \ No newline at end of file diff --git a/.gitpod.yml b/.gitpod.yml deleted file mode 100644 index 96483d7..0000000 --- a/.gitpod.yml +++ /dev/null @@ -1,10 +0,0 @@ -tasks: - - name: open-runtimes/proxy - init: | - docker compose pull - docker compose build - composer install --ignore-platform-reqs -vscode: - extensions: - - ms-azuretools.vscode-docker - - zobo.php-intellisense \ No newline at end of file diff --git a/_build.txt b/_build.txt deleted file mode 100644 index 04412d8..0000000 --- a/_build.txt +++ /dev/null @@ -1,2 +0,0 @@ --- TODO: Convert this to real release process -docker build -t utopia-php/database-proxy:0.1.0 . \ No newline at end of file diff --git a/app/Validator/Assoc.php b/app/Validator/Assoc.php deleted file mode 100644 index 255c8ae..0000000 --- a/app/Validator/Assoc.php +++ /dev/null @@ -1,36 +0,0 @@ - MAX_STRING_SIZE) { - return false; - } - - return \array_keys($value) !== \range(0, \count($value) - 1); - } -} diff --git a/app/endpoints.php b/app/endpoints.php index 85cc041..0a06abd 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -4,19 +4,20 @@ use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; -use Utopia\DatabaseProxy\Validator\Assoc; use Utopia\Http\Http; use Utopia\Http\Response; use Utopia\Http\Validator\ArrayList; +use Utopia\Http\Validator\Assoc; use Utopia\Http\Validator\Boolean; use Utopia\Http\Validator\FloatValidator; use Utopia\Http\Validator\Integer; use Utopia\Http\Validator\Text; -const MAX_ARRAY_SIZE = 100000; -const MAX_STRING_SIZE = 20 * 1024 * 1024; // 20 MB - -// TODO: Do proper methods. Currently all is post +Http::post('/mock/error') + ->groups(['api']) + ->action(function () { + throw new Exception('Mock error', 500); + }); Http::post('/v1/queries/ping') ->groups(['api']) @@ -73,8 +74,8 @@ Http::post('/v1/queries/createCollection') ->groups(['api']) ->param('name', '', new Text(MAX_STRING_SIZE, 0)) - ->param('attributes', [], new ArrayList(new Assoc(), MAX_ARRAY_SIZE), '', true) - ->param('indexes', [], new ArrayList(new Assoc(), MAX_ARRAY_SIZE), '', true) + ->param('attributes', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) + ->param('indexes', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) ->inject('adapter') ->inject('response') ->action(function (string $name, array $attributes, array $indexes, Adapter $adapter, Response $response) { @@ -234,7 +235,7 @@ Http::post('/v1/queries/getCountOfAttributes') ->groups(['api']) - ->param('collection', '', new Assoc()) + ->param('collection', '', new Assoc(MAX_STRING_SIZE)) ->inject('adapter') ->inject('response') ->action(function (array $collection, Adapter $adapter, Response $response) { @@ -249,7 +250,7 @@ Http::post('/v1/queries/getCountOfIndexes') ->groups(['api']) - ->param('collection', '', new Assoc()) + ->param('collection', '', new Assoc(MAX_STRING_SIZE)) ->inject('adapter') ->inject('response') ->action(function (array $collection, Adapter $adapter, Response $response) { @@ -264,7 +265,7 @@ Http::post('/v1/queries/getAttributeWidth') ->groups(['api']) - ->param('collection', '', new Assoc()) + ->param('collection', '', new Assoc(MAX_STRING_SIZE)) ->inject('adapter') ->inject('response') ->action(function (array $collection, Adapter $adapter, Response $response) { @@ -280,7 +281,7 @@ Http::post('/v1/queries/createDocument') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('document', '', new Assoc()) + ->param('document', '', new Assoc(MAX_STRING_SIZE)) ->inject('adapter') ->inject('response') ->action(function (string $collection, array $document, Adapter $adapter, Response $response) { @@ -296,7 +297,7 @@ Http::post('/v1/queries/updateDocument') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('document', '', new Assoc()) + ->param('document', '', new Assoc(MAX_STRING_SIZE)) ->inject('adapter') ->inject('response') ->action(function (string $collection, array $document, Adapter $adapter, Response $response) { @@ -327,7 +328,7 @@ ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('id', '', new Text(MAX_STRING_SIZE, 0)) - ->param('queries', [], new ArrayList(new Assoc(), MAX_ARRAY_SIZE), '', true) + ->param('queries', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) ->inject('adapter') ->inject('response') ->action(function (string $collection, string $id, array $queries, Adapter $adapter, Response $response) { @@ -345,12 +346,12 @@ Http::post('/v1/queries/find') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('queries', [], new ArrayList(new Assoc(), MAX_ARRAY_SIZE), '', true) + ->param('queries', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) ->param('limit', 25, new Integer(), '', true) ->param('offset', null, new Integer(), '', true) ->param('orderAttributes', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) ->param('orderTypes', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) - ->param('cursor', [], new Assoc(), '', true) + ->param('cursor', [], new Assoc(MAX_STRING_SIZE), '', true) ->param('cursorDirection', Database::CURSOR_AFTER, new Text(MAX_STRING_SIZE, 0), '', true) ->param('timeout', null, new Integer(), '', true) ->inject('adapter') @@ -371,7 +372,7 @@ ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) - ->param('queries', [], new ArrayList(new Assoc(), MAX_ARRAY_SIZE), '', true) + ->param('queries', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) ->param('max', null, new Integer(), '', true) ->param('timeout', null, new Integer(), '', true) ->inject('adapter') @@ -391,7 +392,7 @@ Http::post('/v1/queries/count') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('queries', [], new ArrayList(new Assoc(), MAX_ARRAY_SIZE), '', true) + ->param('queries', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) ->param('max', null, new Integer(), '', true) ->param('timeout', null, new Integer(), '', true) ->inject('adapter') diff --git a/app/http.php b/app/http.php index fe5c5c8..6b04ffb 100644 --- a/app/http.php +++ b/app/http.php @@ -10,14 +10,47 @@ use Utopia\Http\Http; use Utopia\Http\Request; use Utopia\Http\Response; +use Utopia\Http\Route; +use Utopia\Logger\Adapter\AppSignal; +use Utopia\Logger\Adapter\LogOwl; +use Utopia\Logger\Adapter\Raygun; +use Utopia\Logger\Adapter\Sentry; +use Utopia\Logger\Log; +use Utopia\Logger\Logger; use Utopia\Registry\Registry; use function Swoole\Coroutine\run; +const MAX_ARRAY_SIZE = 100000; +const MAX_STRING_SIZE = 20 * 1024 * 1024; // 20 MB +const PAYLOAD_SIZE = 20 * 1024 * 1024; // 20MB + require_once __DIR__ . '/endpoints.php'; +Http::setMode((string) Http::getEnv('UTOPIA_DATABASE_PROXY_ENV', Http::MODE_TYPE_PRODUCTION)); + $registry = new Registry(); +$registry->set('logger', function () { + $providerName = Http::getEnv('UTOPIA_DATABASE_PROXY_LOGGING_PROVIDER', ''); + $providerConfig = Http::getEnv('UTOPIA_DATABASE_PROXY_LOGGING_CONFIG', ''); + $logger = null; + + if (!empty($providerName) && !empty($providerConfig) && Logger::hasProvider($providerName)) { + $adapter = match ($providerName) { + 'sentry' => new Sentry($providerConfig), + 'raygun' => new Raygun($providerConfig), + 'logowl' => new LogOwl($providerConfig), + 'appsignal' => new AppSignal($providerConfig), + default => throw new Exception('Provider "' . $providerName . '" not supported.') + }; + + $logger = new Logger($adapter); + } + + return $logger; +}); + $registry->set('adapters', function () { $dsns = \explode(',', Http::getEnv('UTOPIA_DATABASE_PROXY_SECRET_CONNECTIONS', '') ?? ''); @@ -42,7 +75,7 @@ PDO::ATTR_TIMEOUT => 15, // Seconds PDO::ATTR_PERSISTENT => false, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - // PDO::ATTR_ERRMODE => Http::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed + PDO::ATTR_ERRMODE => Http::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed PDO::ATTR_EMULATE_PREPARES => true, PDO::ATTR_STRINGIFY_FETCHES => true )); @@ -59,15 +92,13 @@ $http = new Server("0.0.0.0", Http::getEnv('UTOPIA_DATABASE_PROXY_PORT', '80')); -$payloadSize = 20 * (1024 * 1024); // 20MB - $http ->setConfig([ 'open_http2_protocol' => true, 'http_compression' => true, 'http_compression_level' => 6, - 'package_max_length' => $payloadSize, - 'buffer_output_size' => $payloadSize, + 'package_max_length' => PAYLOAD_SIZE, + 'buffer_output_size' => PAYLOAD_SIZE, ]); Http::onStart() @@ -76,8 +107,9 @@ }); Http::setResource('registry', fn () => $registry); - +Http::setResource('logger', fn (Registry $registry) => $registry->get('logger'), ['registry']); Http::setResource('adapters', fn (Registry $registry) => $registry->get('adapters'), ['registry']); +Http::setResource('log', fn () => new Log()); Http::setResource('adapter', function (Request $request, array $adapters) { $database = $request->getHeader('x-utopia-database', ''); @@ -150,11 +182,55 @@ } }); +function logError(Log $log, Throwable $error, string $action, Logger $logger = null, ?Route $route = null): void +{ + Console::error('[Error] Type: ' . get_class($error)); + Console::error('[Error] Message: ' . $error->getMessage()); + Console::error('[Error] File: ' . $error->getFile()); + Console::error('[Error] Line: ' . $error->getLine()); + + if ($logger && ($error->getCode() === 500 || $error->getCode() === 0)) { + $version = (string) Http::getEnv('UTOPIA_DATABASE_PROXY_VERSION', ''); + if (empty($version)) { + $version = 'UNKNOWN'; + } + + $log->setNamespace("database-proxy"); + $log->setServer(\gethostname() !== false ? \gethostname() : null); + $log->setVersion($version); + $log->setType(Log::TYPE_ERROR); + $log->setMessage($error->getMessage()); + + if ($route) { + $log->addTag('method', $route->getMethod()); + $log->addTag('url', $route->getPath()); + } + + $log->addTag('code', \strval($error->getCode())); + $log->addTag('verboseType', get_class($error)); + + $log->addExtra('file', $error->getFile()); + $log->addExtra('line', $error->getLine()); + $log->addExtra('trace', $error->getTraceAsString()); + $log->addExtra('detailedTrace', $error->getTrace()); + + $log->setAction($action); + + $log->setEnvironment(Http::isProduction() ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); + + $responseCode = $logger->addLog($log); + Console::info('Log pushed with status code: ' . $responseCode); + } +} + Http::error() + ->inject('route') ->inject('error') + ->inject('logger') ->inject('response') - ->action(function (Throwable $error, Response $response) { - // TODO: Log to Sentry + ->inject('log') + ->action(function (?Route $route, Throwable $error, ?Logger $logger, Response $response, Log $log) { + logError($log, $error, "httpError", $logger, $route); switch ($error->getCode()) { case 400: // Error allowed publicly diff --git a/composer.json b/composer.json index 5a768b5..2fe53e5 100644 --- a/composer.json +++ b/composer.json @@ -8,29 +8,36 @@ "Utopia\\DatabaseProxy\\": "app" } }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests" + } + }, "scripts": { "lint": "./vendor/bin/pint --preset psr12 --test", "format": "./vendor/bin/pint --preset psr12", - "check": "./vendor/bin/phpstan analyse --level 8 -c phpstan.neon app", + "check": "./vendor/bin/phpstan analyse --level 8 -c phpstan.neon app tests", "test": "./vendor/bin/phpunit --configuration phpunit.xml --debug" }, "require": { "php": ">=8.0.0", "ext-curl": "*", "ext-json": "*", - "ext-swoole": "*" + "ext-swoole": "*", + "utopia-php/framework": "dev-fix-v2-swoole-coroutines as 0.32.99", + "utopia-php/database": "dev-feat-framework-v2 as 0.44.99", + "utopia-php/cache": "0.8.*", + "utopia-php/cli": "0.16.*", + "utopia-php/registry": "0.6.*", + "utopia-php/dsn": "0.1.*", + "utopia-php/logger": "0.3.*" }, "require-dev": { "swoole/ide-helper": "4.8.5", "phpunit/phpunit": "^9.3", "laravel/pint": "1.2.*", "phpstan/phpstan": "1.8.*", - "utopia-php/framework": "dev-fix-v2-swoole-coroutines as 0.32.99", - "utopia-php/database": "dev-feat-framework-v2 as 0.44.99", - "utopia-php/cache": "0.8.*", - "utopia-php/cli": "0.16.*", - "utopia-php/registry": "0.6.*", - "utopia-php/dsn": "0.1.*" + "utopia-php/fetch": "0.1.*" }, "config": { "platform": { diff --git a/composer.lock b/composer.lock index 04f6dd6..7f77937 100644 --- a/composer.lock +++ b/composer.lock @@ -4,79 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "184f24da457f75e89e7f05b150b8802d", - "packages": [], - "packages-dev": [ - { - "name": "doctrine/instantiator", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "require-dev": { - "doctrine/coding-standard": "^11", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^1.2", - "phpstan/phpstan": "^1.9.4", - "phpstan/phpstan-phpunit": "^1.3", - "phpunit/phpunit": "^9.5.27", - "vimeo/psalm": "^5.4" - }, - "type": "library", - "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": "https://ocramius.github.io/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/2.0.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2022-12-30T00:23:10+00:00" - }, + "content-hash": "194f0f452f37dc2b1ddccdfb06f1f5be", + "packages": [ { "name": "jean85/pretty-package-versions", "version": "2.0.5", @@ -136,72 +65,6 @@ }, "time": "2021-10-08T21:21:46+00:00" }, - { - "name": "laravel/pint", - "version": "v1.2.1", - "source": { - "type": "git", - "url": "https://github.com/laravel/pint.git", - "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/e60e2112ee779ce60f253695b273d1646a17d6f1", - "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-mbstring": "*", - "ext-tokenizer": "*", - "ext-xml": "*", - "php": "^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.11.0", - "illuminate/view": "^9.32.0", - "laravel-zero/framework": "^9.2.0", - "mockery/mockery": "^1.5.1", - "nunomaduro/larastan": "^2.2.0", - "nunomaduro/termwind": "^1.14.0", - "pestphp/pest": "^1.22.1" - }, - "bin": [ - "builds/pint" - ], - "type": "project", - "autoload": { - "psr-4": { - "App\\": "app/", - "Database\\Seeders\\": "database/seeders/", - "Database\\Factories\\": "database/factories/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" - } - ], - "description": "An opinionated code formatter for PHP.", - "homepage": "https://laravel.com", - "keywords": [ - "format", - "formatter", - "lint", - "linter", - "php" - ], - "support": { - "issues": "https://github.com/laravel/pint/issues", - "source": "https://github.com/laravel/pint" - }, - "time": "2022-11-29T16:25:20+00:00" - }, { "name": "mongodb/mongodb", "version": "1.10.0", @@ -272,521 +135,733 @@ "time": "2021-10-20T22:22:37+00:00" }, { - "name": "myclabs/deep-copy", - "version": "1.11.1", + "name": "symfony/polyfill-php80", + "version": "v1.28.0", "source": { "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" - }, - "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + "php": ">=7.1" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, "autoload": { "files": [ - "src/DeepCopy/deep_copy.php" + "bootstrap.php" ], "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Create deep copies (clones) of your objects", + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" + "compatibility", + "polyfill", + "portable", + "shim" ], "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" }, "funding": [ { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2023-03-08T13:26:56+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { - "name": "nikic/php-parser", - "version": "v4.17.1", + "name": "utopia-php/cache", + "version": "0.8.0", "source": { "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + "url": "https://github.com/utopia-php/cache.git", + "reference": "212e66100a1f32e674fca5d9bc317cc998303089" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "url": "https://api.github.com/repos/utopia-php/cache/zipball/212e66100a1f32e674fca5d9bc317cc998303089", + "reference": "212e66100a1f32e674fca5d9bc317cc998303089", "shasum": "" }, "require": { - "ext-tokenizer": "*", - "php": ">=7.0" + "ext-json": "*", + "ext-memcached": "*", + "ext-redis": "*", + "php": ">=8.0" }, "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "laravel/pint": "1.2.*", + "phpunit/phpunit": "^9.3", + "vimeo/psalm": "4.13.1" }, - "bin": [ - "bin/php-parse" - ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.9-dev" - } - }, "autoload": { "psr-4": { - "PhpParser\\": "lib/PhpParser" + "Utopia\\Cache\\": "src/Cache" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], - "authors": [ - { - "name": "Nikita Popov" + "description": "A simple cache library to manage application cache storing, loading and purging", + "keywords": [ + "cache", + "framework", + "php", + "upf", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/cache/issues", + "source": "https://github.com/utopia-php/cache/tree/0.8.0" + }, + "time": "2022-10-16T16:48:09+00:00" + }, + { + "name": "utopia-php/cli", + "version": "0.16.0", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/cli.git", + "reference": "5b936638c90c86d1bae83d0dbe81fe14d12ff8ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/cli/zipball/5b936638c90c86d1bae83d0dbe81fe14d12ff8ff", + "reference": "5b936638c90c86d1bae83d0dbe81fe14d12ff8ff", + "shasum": "" + }, + "require": { + "php": ">=7.4", + "utopia-php/framework": "0.*.*" + }, + "require-dev": { + "laravel/pint": "1.2.*", + "phpunit/phpunit": "^9.3", + "squizlabs/php_codesniffer": "^3.6", + "vimeo/psalm": "4.0.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\CLI\\": "src/CLI" } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" ], - "description": "A PHP parser written in PHP", + "description": "A simple CLI library to manage command line applications", "keywords": [ - "parser", - "php" + "cli", + "command line", + "framework", + "php", + "upf", + "utopia" ], "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + "issues": "https://github.com/utopia-php/cli/issues", + "source": "https://github.com/utopia-php/cli/tree/0.16.0" }, - "time": "2023-08-13T19:53:39+00:00" + "time": "2023-08-05T13:13:08+00:00" }, { - "name": "phar-io/manifest", - "version": "2.0.3", + "name": "utopia-php/database", + "version": "dev-feat-framework-v2", "source": { "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "url": "https://github.com/utopia-php/database.git", + "reference": "1d4ab3dfafbe7a3adfd167e5e288c19634c223ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/utopia-php/database/zipball/1d4ab3dfafbe7a3adfd167e5e288c19634c223ce", + "reference": "1d4ab3dfafbe7a3adfd167e5e288c19634c223ce", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" + "ext-mbstring": "*", + "ext-pdo": "*", + "php": ">=8.0", + "utopia-php/cache": "0.8.*", + "utopia-php/framework": "dev-fix-v2-swoole-coroutines as 0.31.0", + "utopia-php/mongo": "0.3.*" + }, + "require-dev": { + "fakerphp/faker": "^1.14", + "laravel/pint": "1.4.*", + "pcov/clobber": "^2.0", + "phpstan/phpstan": "1.10.*", + "phpunit/phpunit": "^9.4", + "rregeer/phpunit-coverage-check": "^0.3.1", + "swoole/ide-helper": "4.8.0", + "utopia-php/cli": "^0.14.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" + "autoload": { + "psr-4": { + "Utopia\\Database\\": "src/Database" } }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A simple library to manage application persistence using multiple database adapters", + "keywords": [ + "database", + "framework", + "php", + "upf", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/database/issues", + "source": "https://github.com/utopia-php/database/tree/feat-framework-v2" + }, + "time": "2023-10-05T09:43:50+00:00" + }, + { + "name": "utopia-php/dsn", + "version": "0.1.0", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/dsn.git", + "reference": "17a5935eab1b89fb4b95600db50a1b6d5faa6cea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/dsn/zipball/17a5935eab1b89fb4b95600db50a1b6d5faa6cea", + "reference": "17a5935eab1b89fb4b95600db50a1b6d5faa6cea", + "shasum": "" + }, + "require": { + "php": ">=8.0" + }, + "require-dev": { + "laravel/pint": "1.2.*", + "phpunit/phpunit": "^9.3", + "squizlabs/php_codesniffer": "^3.6", + "vimeo/psalm": "4.0.1" + }, + "type": "library", "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Utopia\\DSN\\": "src/DSN" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" + "description": "A simple library for parsing and managing Data Source Names ( DSNs )", + "keywords": [ + "dsn", + "framework", + "php", + "upf", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/dsn/issues", + "source": "https://github.com/utopia-php/dsn/tree/0.1.0" + }, + "time": "2022-10-26T10:06:20+00:00" + }, + { + "name": "utopia-php/framework", + "version": "dev-fix-v2-swoole-coroutines", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/framework.git", + "reference": "7405c1fea69443c9034c2f6494a7cbd2d6e6813f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/7405c1fea69443c9034c2f6494a7cbd2d6e6813f", + "reference": "7405c1fea69443c9034c2f6494a7cbd2d6e6813f", + "shasum": "" + }, + "require": { + "ext-swoole": "*", + "php": ">=8.0" + }, + "require-dev": { + "laravel/pint": "^1.2", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.25", + "swoole/ide-helper": "4.8.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Http\\": "src/Http" } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A simple, light and advanced PHP framework", + "keywords": [ + "framework", + "php", + "upf" ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { - "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "issues": "https://github.com/utopia-php/framework/issues", + "source": "https://github.com/utopia-php/framework/tree/fix-v2-swoole-coroutines" }, - "time": "2021-07-20T11:28:43+00:00" + "time": "2023-10-17T11:16:05+00:00" }, { - "name": "phar-io/version", - "version": "3.2.1", + "name": "utopia-php/logger", + "version": "0.3.1", "source": { "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + "url": "https://github.com/utopia-php/logger.git", + "reference": "de623f1ec1c672c795d113dd25c5bf212f7ef4fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "url": "https://api.github.com/repos/utopia-php/logger/zipball/de623f1ec1c672c795d113dd25c5bf212f7ef4fc", + "reference": "de623f1ec1c672c795d113dd25c5bf212f7ef4fc", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": ">=8.0" + }, + "require-dev": { + "phpstan/phpstan": "1.9.x-dev", + "phpunit/phpunit": "^9.3", + "vimeo/psalm": "4.0.1" }, "type": "library", "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Utopia\\Logger\\": "src/Logger" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, + "description": "Utopia Logger library is simple and lite library for logging information, such as errors or warnings. This library is aiming to be as simple and easy to learn and use.", + "keywords": [ + "appsignal", + "errors", + "framework", + "logger", + "logging", + "logs", + "php", + "raygun", + "sentry", + "upf", + "utopia", + "warnings" + ], + "support": { + "issues": "https://github.com/utopia-php/logger/issues", + "source": "https://github.com/utopia-php/logger/tree/0.3.1" + }, + "time": "2023-02-10T15:52:50+00:00" + }, + { + "name": "utopia-php/mongo", + "version": "0.3.1", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/mongo.git", + "reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/mongo/zipball/52326a9a43e2d27ff0c15c48ba746dacbe9a7aee", + "reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee", + "shasum": "" + }, + "require": { + "ext-mongodb": "*", + "mongodb/mongodb": "1.10.0", + "php": ">=8.0" + }, + "require-dev": { + "fakerphp/faker": "^1.14", + "laravel/pint": "1.2.*", + "phpstan/phpstan": "1.8.*", + "phpunit/phpunit": "^9.4", + "swoole/ide-helper": "4.8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Mongo\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" + "name": "Eldad Fux", + "email": "eldad@appwrite.io" }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" + "name": "Wess", + "email": "wess@appwrite.io" } ], - "description": "Library for handling version information and constraints", + "description": "A simple library to manage Mongo database", + "keywords": [ + "database", + "mongo", + "php", + "upf", + "utopia" + ], "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.2.1" + "issues": "https://github.com/utopia-php/mongo/issues", + "source": "https://github.com/utopia-php/mongo/tree/0.3.1" }, - "time": "2022-02-21T01:04:05+00:00" + "time": "2023-09-01T17:25:28+00:00" }, { - "name": "phpstan/phpstan", - "version": "1.8.11", + "name": "utopia-php/registry", + "version": "0.6.0", "source": { "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "46e223dd68a620da18855c23046ddb00940b4014" + "url": "https://github.com/utopia-php/registry.git", + "reference": "9c183312e48c926135085f34ac2e73dadb83e0c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/46e223dd68a620da18855c23046ddb00940b4014", - "reference": "46e223dd68a620da18855c23046ddb00940b4014", + "url": "https://api.github.com/repos/utopia-php/registry/zipball/9c183312e48c926135085f34ac2e73dadb83e0c8", + "reference": "9c183312e48c926135085f34ac2e73dadb83e0c8", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "php": ">=7.4" }, - "conflict": { - "phpstan/phpstan-shim": "*" + "require-dev": { + "phpunit/phpunit": "^9.3", + "vimeo/psalm": "4.0.1" }, - "bin": [ - "phpstan", - "phpstan.phar" - ], "type": "library", "autoload": { - "files": [ - "bootstrap.php" - ] + "psr-4": { + "Utopia\\Registry\\": "src/Registry" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "PHPStan - PHP Static Analysis Tool", + "authors": [ + { + "name": "Eldad Fux", + "email": "eldad@appwrite.io" + } + ], + "description": "A simple dependency management library for PHP", "keywords": [ - "dev", - "static analysis" + "dependency management", + "di", + "framework", + "php", + "upf", + "utopia" ], "support": { - "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.8.11" + "issues": "https://github.com/utopia-php/registry/issues", + "source": "https://github.com/utopia-php/registry/tree/0.6.0" }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" - } - ], - "time": "2022-10-24T15:45:13+00:00" - }, + "time": "2022-07-17T15:26:57+00:00" + } + ], + "packages-dev": [ { - "name": "phpunit/php-code-coverage", - "version": "9.2.29", + "name": "doctrine/instantiator", + "version": "2.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-xmlwriter": "*", - "nikic/php-parser": "^4.15", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "php": "^8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcov": "PHP extension that provides line coverage", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.2-dev" - } - }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" } ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ - "coverage", - "testing", - "xunit" + "constructor", + "instantiate" ], "support": { - "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" } ], - "time": "2023-09-19T04:57:46+00:00" + "time": "2022-12-30T00:23:10+00:00" }, { - "name": "phpunit/php-file-iterator", - "version": "3.0.6", + "name": "laravel/pint", + "version": "v1.2.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + "url": "https://github.com/laravel/pint.git", + "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "url": "https://api.github.com/repos/laravel/pint/zipball/e60e2112ee779ce60f253695b273d1646a17d6f1", + "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1", "shasum": "" }, "require": { - "php": ">=7.3" + "ext-json": "*", + "ext-mbstring": "*", + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } + "friendsofphp/php-cs-fixer": "^3.11.0", + "illuminate/view": "^9.32.0", + "laravel-zero/framework": "^9.2.0", + "mockery/mockery": "^1.5.1", + "nunomaduro/larastan": "^2.2.0", + "nunomaduro/termwind": "^1.14.0", + "pestphp/pest": "^1.22.1" }, + "bin": [ + "builds/pint" + ], + "type": "project", "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "App\\": "app/", + "Database\\Seeders\\": "database/seeders/", + "Database\\Factories\\": "database/factories/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" } ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "description": "An opinionated code formatter for PHP.", + "homepage": "https://laravel.com", "keywords": [ - "filesystem", - "iterator" + "format", + "formatter", + "lint", + "linter", + "php" ], "support": { - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2021-12-02T12:48:52+00:00" + "time": "2022-11-29T16:25:20+00:00" }, { - "name": "phpunit/php-invoker", - "version": "3.1.1", + "name": "myclabs/deep-copy", + "version": "1.11.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "shasum": "" }, "require": { - "php": ">=7.3" + "php": "^7.1 || ^8.0" }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" }, - "suggest": { - "ext-pcntl": "*" + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, "autoload": { - "classmap": [ - "src/" - ] + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } + "MIT" ], - "description": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "description": "Create deep copies (clones) of your objects", "keywords": [ - "process" + "clone", + "copy", + "duplicate", + "object", + "object graph" ], "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" } ], - "time": "2020-09-28T05:58:55+00:00" + "time": "2023-03-08T13:26:56+00:00" }, { - "name": "phpunit/php-text-template", - "version": "2.0.4", + "name": "nikic/php-parser", + "version": "v4.17.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", "shasum": "" }, "require": { - "php": ">=7.3" + "ext-tokenizer": "*", + "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" }, + "bin": [ + "bin/php-parse" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "4.9-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -794,52 +869,45 @@ ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Nikita Popov" } ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "description": "A PHP parser written in PHP", "keywords": [ - "template" + "parser", + "php" ], "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T05:33:50+00:00" + "time": "2023-08-13T19:53:39+00:00" }, { - "name": "phpunit/php-timer", - "version": "5.0.3", + "name": "phar-io/manifest", + "version": "2.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", "shasum": "" }, "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -852,89 +920,48 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", - "role": "lead" + "role": "Developer" } ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:16:10+00:00" + "time": "2021-07-20T11:28:43+00:00" }, { - "name": "phpunit/phpunit", - "version": "9.6.13", + "name": "phar-io/version", + "version": "3.2.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1 || ^2", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", - "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.28", - "phpunit/php-file-iterator": "^3.0.5", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", - "sebastian/version": "^3.0.2" - }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + "php": "^7.2 || ^8.0" }, - "bin": [ - "phpunit" - ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.6-dev" - } - }, "autoload": { - "files": [ - "src/Framework/Assert/Functions.php" - ], "classmap": [ "src/" ] @@ -945,119 +972,127 @@ ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" - }, - "funding": [ - { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" }, { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" }, { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" } ], - "time": "2023-09-19T05:39:22+00:00" + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" }, { - "name": "sebastian/cli-parser", - "version": "1.0.1", + "name": "phpstan/phpstan", + "version": "1.8.11", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "url": "https://github.com/phpstan/phpstan.git", + "reference": "46e223dd68a620da18855c23046ddb00940b4014" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/46e223dd68a620da18855c23046ddb00940b4014", + "reference": "46e223dd68a620da18855c23046ddb00940b4014", "shasum": "" }, "require": { - "php": ">=7.3" + "php": "^7.2|^8.0" }, - "require-dev": { - "phpunit/phpunit": "^9.3" + "conflict": { + "phpstan/phpstan-shim": "*" }, + "bin": [ + "phpstan", + "phpstan.phar" + ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "files": [ + "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "issues": "https://github.com/phpstan/phpstan/issues", + "source": "https://github.com/phpstan/phpstan/tree/1.8.11" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2022-10-24T15:45:13+00:00" }, { - "name": "sebastian/code-unit", - "version": "1.0.8", + "name": "phpunit/php-code-coverage", + "version": "9.2.29", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", "shasum": "" }, "require": { - "php": ">=7.3" + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.15", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" }, "require-dev": { "phpunit/phpunit": "^9.3" }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "9.2-dev" } }, "autoload": { @@ -1076,11 +1111,17 @@ "role": "lead" } ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", + "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" + ], "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" }, "funding": [ { @@ -1088,20 +1129,20 @@ "type": "github" } ], - "time": "2020-10-26T13:08:54+00:00" + "time": "2023-09-19T04:57:46+00:00" }, { - "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", + "name": "phpunit/php-file-iterator", + "version": "3.0.6", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", "shasum": "" }, "require": { @@ -1113,7 +1154,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1128,14 +1169,19 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" }, "funding": [ { @@ -1143,34 +1189,36 @@ "type": "github" } ], - "time": "2020-09-28T05:30:19+00:00" + "time": "2021-12-02T12:48:52+00:00" }, { - "name": "sebastian/comparator", - "version": "4.0.8", + "name": "phpunit/php-invoker", + "version": "3.1.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" + "php": ">=7.3" }, "require-dev": { + "ext-pcntl": "*", "phpunit/phpunit": "^9.3" }, + "suggest": { + "ext-pcntl": "*" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -1185,31 +1233,18 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", "keywords": [ - "comparator", - "compare", - "equality" + "process" ], "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" }, "funding": [ { @@ -1217,24 +1252,23 @@ "type": "github" } ], - "time": "2022-09-14T12:41:17+00:00" + "time": "2020-09-28T05:58:55+00:00" }, { - "name": "sebastian/complexity", - "version": "2.0.2", + "name": "phpunit/php-text-template", + "version": "2.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", "php": ">=7.3" }, "require-dev": { @@ -1262,11 +1296,14 @@ "role": "lead" } ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" }, "funding": [ { @@ -1274,33 +1311,32 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2020-10-26T05:33:50+00:00" }, { - "name": "sebastian/diff", - "version": "4.0.5", + "name": "phpunit/php-timer", + "version": "5.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", "shasum": "" }, "require": { "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -1315,24 +1351,18 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" + "timer" ], "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" }, "funding": [ { @@ -1340,38 +1370,68 @@ "type": "github" } ], - "time": "2023-05-07T05:35:17+00:00" + "time": "2020-10-26T13:16:10+00:00" }, { - "name": "sebastian/environment", - "version": "5.1.5", + "name": "phpunit/phpunit", + "version": "9.6.13", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", "shasum": "" }, "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" + "doctrine/instantiator": "^1.3.1 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.28", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" }, "suggest": { - "ext-posix": "*" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, + "bin": [ + "phpunit" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-master": "9.6-dev" } }, "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], "classmap": [ "src/" ] @@ -1383,54 +1443,62 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", "keywords": [ - "Xdebug", - "environment", - "hhvm" + "phpunit", + "testing", + "xunit" ], "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" }, "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" } ], - "time": "2023-02-03T06:03:51+00:00" + "time": "2023-09-19T05:39:22+00:00" }, { - "name": "sebastian/exporter", - "version": "4.0.5", + "name": "sebastian/cli-parser", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" + "php": ">=7.3" }, "require-dev": { - "ext-mbstring": "*", "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -1445,34 +1513,15 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "https://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" }, "funding": [ { @@ -1480,38 +1529,32 @@ "type": "github" } ], - "time": "2022-09-14T06:03:37+00:00" + "time": "2020-09-28T06:08:49+00:00" }, { - "name": "sebastian/global-state", - "version": "5.0.6", + "name": "sebastian/code-unit", + "version": "1.0.8", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bde739e7565280bda77be70044ac1047bc007e34" + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", - "reference": "bde739e7565280bda77be70044ac1047bc007e34", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=7.3" }, "require-dev": { - "ext-dom": "*", "phpunit/phpunit": "^9.3" }, - "suggest": { - "ext-uopz": "*" - }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -1526,17 +1569,15 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" }, "funding": [ { @@ -1544,24 +1585,23 @@ "type": "github" } ], - "time": "2023-08-02T09:26:13+00:00" + "time": "2020-10-26T13:08:54+00:00" }, { - "name": "sebastian/lines-of-code", - "version": "1.0.3", + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", "php": ">=7.3" }, "require-dev": { @@ -1570,7 +1610,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1585,15 +1625,14 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" } ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" }, "funding": [ { @@ -1601,26 +1640,26 @@ "type": "github" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2020-09-28T05:30:19+00:00" }, { - "name": "sebastian/object-enumerator", - "version": "4.0.4", + "name": "sebastian/comparator", + "version": "4.0.8", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", "shasum": "" }, "require": { "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" }, "require-dev": { "phpunit/phpunit": "^9.3" @@ -1644,13 +1683,30 @@ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" } ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], "support": { - "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" }, "funding": [ { @@ -1658,23 +1714,24 @@ "type": "github" } ], - "time": "2020-10-26T13:12:34+00:00" + "time": "2022-09-14T12:41:17+00:00" }, { - "name": "sebastian/object-reflector", - "version": "2.0.4", + "name": "sebastian/complexity", + "version": "2.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", "shasum": "" }, "require": { + "nikic/php-parser": "^4.7", "php": ">=7.3" }, "require-dev": { @@ -1698,14 +1755,15 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", "support": { - "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" }, "funding": [ { @@ -1713,27 +1771,28 @@ "type": "github" } ], - "time": "2020-10-26T13:14:26+00:00" + "time": "2020-10-26T15:52:27+00:00" }, { - "name": "sebastian/recursion-context", + "name": "sebastian/diff", "version": "4.0.5", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" }, "type": "library", "extra": { @@ -1756,19 +1815,21 @@ "email": "sebastian@phpunit.de" }, { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" } ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "https://github.com/sebastianbergmann/recursion-context", + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" }, "funding": [ { @@ -1776,32 +1837,35 @@ "type": "github" } ], - "time": "2023-02-03T06:07:39+00:00" + "time": "2023-05-07T05:35:17+00:00" }, { - "name": "sebastian/resource-operations", - "version": "3.0.3", + "name": "sebastian/environment", + "version": "5.1.5", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", "shasum": "" }, "require": { "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "5.1-dev" } }, "autoload": { @@ -1819,11 +1883,16 @@ "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", + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" }, "funding": [ { @@ -1831,32 +1900,34 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2023-02-03T06:03:51+00:00" }, { - "name": "sebastian/type", - "version": "3.2.1", + "name": "sebastian/exporter", + "version": "4.0.5", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^9.5" + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1871,15 +1942,34 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], - "description": "Collection of value objects that represent the types of the PHP type system", - "homepage": "https://github.com/sebastianbergmann/type", + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], "support": { - "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" }, "funding": [ { @@ -1887,29 +1977,38 @@ "type": "github" } ], - "time": "2023-02-03T06:13:03+00:00" + "time": "2022-09-14T06:03:37+00:00" }, { - "name": "sebastian/version", - "version": "3.0.2", + "name": "sebastian/global-state", + "version": "5.0.6", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bde739e7565280bda77be70044ac1047bc007e34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -1924,15 +2023,17 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" } ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" }, "funding": [ { @@ -1940,154 +2041,148 @@ "type": "github" } ], - "time": "2020-09-28T06:39:44+00:00" + "time": "2023-08-02T09:26:13+00:00" }, { - "name": "swoole/ide-helper", - "version": "4.8.5", + "name": "sebastian/lines-of-code", + "version": "1.0.3", "source": { "type": "git", - "url": "https://github.com/swoole/ide-helper.git", - "reference": "d03c707d4dc803228e93b4884c72949c4d28e8b8" + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swoole/ide-helper/zipball/d03c707d4dc803228e93b4884c72949c4d28e8b8", - "reference": "d03c707d4dc803228e93b4884c72949c4d28e8b8", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", "shasum": "" }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache-2.0" + "BSD-3-Clause" ], "authors": [ { - "name": "Team Swoole", - "email": "team@swoole.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "IDE help files for Swoole.", + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { - "issues": "https://github.com/swoole/ide-helper/issues", - "source": "https://github.com/swoole/ide-helper/tree/4.8.5" + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" }, "funding": [ { - "url": "https://gitee.com/swoole/swoole?donate=true", - "type": "custom" - }, - { - "url": "https://github.com/swoole", + "url": "https://github.com/sebastianbergmann", "type": "github" } ], - "time": "2021-12-24T22:44:20+00:00" + "time": "2020-11-28T06:42:11+00:00" }, { - "name": "symfony/polyfill-php80", - "version": "v1.28.0", + "name": "sebastian/object-enumerator", + "version": "4.0.4", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "dev-master": "4.0-dev" } }, "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, "classmap": [ - "Resources/stubs" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2020-10-26T13:12:34+00:00" }, { - "name": "theseer/tokenizer", - "version": "1.2.1", + "name": "sebastian/object-reflector", + "version": "2.0.4", "source": { "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.2 || ^8.0" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -2099,383 +2194,381 @@ ], "authors": [ { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { - "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" }, "funding": [ { - "url": "https://github.com/theseer", + "url": "https://github.com/sebastianbergmann", "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" + "time": "2020-10-26T13:14:26+00:00" }, { - "name": "utopia-php/cache", - "version": "0.8.0", + "name": "sebastian/recursion-context", + "version": "4.0.5", "source": { "type": "git", - "url": "https://github.com/utopia-php/cache.git", - "reference": "212e66100a1f32e674fca5d9bc317cc998303089" + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/cache/zipball/212e66100a1f32e674fca5d9bc317cc998303089", - "reference": "212e66100a1f32e674fca5d9bc317cc998303089", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", "shasum": "" }, "require": { - "ext-json": "*", - "ext-memcached": "*", - "ext-redis": "*", - "php": ">=8.0" + "php": ">=7.3" }, "require-dev": { - "laravel/pint": "1.2.*", - "phpunit/phpunit": "^9.3", - "vimeo/psalm": "4.13.1" + "phpunit/phpunit": "^9.3" }, "type": "library", - "autoload": { - "psr-4": { - "Utopia\\Cache\\": "src/Cache" + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], - "description": "A simple cache library to manage application cache storing, loading and purging", - "keywords": [ - "cache", - "framework", - "php", - "upf", - "utopia" + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { - "issues": "https://github.com/utopia-php/cache/issues", - "source": "https://github.com/utopia-php/cache/tree/0.8.0" + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" }, - "time": "2022-10-16T16:48:09+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" }, { - "name": "utopia-php/cli", - "version": "0.16.0", + "name": "sebastian/resource-operations", + "version": "3.0.3", "source": { "type": "git", - "url": "https://github.com/utopia-php/cli.git", - "reference": "5b936638c90c86d1bae83d0dbe81fe14d12ff8ff" + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/cli/zipball/5b936638c90c86d1bae83d0dbe81fe14d12ff8ff", - "reference": "5b936638c90c86d1bae83d0dbe81fe14d12ff8ff", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", "shasum": "" }, "require": { - "php": ">=7.4", - "utopia-php/framework": "0.*.*" + "php": ">=7.3" }, "require-dev": { - "laravel/pint": "1.2.*", - "phpunit/phpunit": "^9.3", - "squizlabs/php_codesniffer": "^3.6", - "vimeo/psalm": "4.0.1" + "phpunit/phpunit": "^9.0" }, "type": "library", - "autoload": { - "psr-4": { - "Utopia\\CLI\\": "src/CLI" + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], - "description": "A simple CLI library to manage command line applications", - "keywords": [ - "cli", - "command line", - "framework", - "php", - "upf", - "utopia" + "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", "support": { - "issues": "https://github.com/utopia-php/cli/issues", - "source": "https://github.com/utopia-php/cli/tree/0.16.0" + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" }, - "time": "2023-08-05T13:13:08+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" }, { - "name": "utopia-php/database", - "version": "dev-feat-framework-v2", + "name": "sebastian/type", + "version": "3.2.1", "source": { "type": "git", - "url": "https://github.com/utopia-php/database.git", - "reference": "1d4ab3dfafbe7a3adfd167e5e288c19634c223ce" + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/1d4ab3dfafbe7a3adfd167e5e288c19634c223ce", - "reference": "1d4ab3dfafbe7a3adfd167e5e288c19634c223ce", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "ext-pdo": "*", - "php": ">=8.0", - "utopia-php/cache": "0.8.*", - "utopia-php/framework": "dev-fix-v2-swoole-coroutines as 0.31.0", - "utopia-php/mongo": "0.3.*" - }, - "require-dev": { - "fakerphp/faker": "^1.14", - "laravel/pint": "1.4.*", - "pcov/clobber": "^2.0", - "phpstan/phpstan": "1.10.*", - "phpunit/phpunit": "^9.4", - "rregeer/phpunit-coverage-check": "^0.3.1", - "swoole/ide-helper": "4.8.0", - "utopia-php/cli": "^0.14.0" + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" }, "type": "library", - "autoload": { - "psr-4": { - "Utopia\\Database\\": "src/Database" + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], - "description": "A simple library to manage application persistence using multiple database adapters", - "keywords": [ - "database", - "framework", - "php", - "upf", - "utopia" + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", "support": { - "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/feat-framework-v2" + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" }, - "time": "2023-10-05T09:43:50+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" }, { - "name": "utopia-php/dsn", - "version": "0.1.0", + "name": "sebastian/version", + "version": "3.0.2", "source": { "type": "git", - "url": "https://github.com/utopia-php/dsn.git", - "reference": "17a5935eab1b89fb4b95600db50a1b6d5faa6cea" + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/dsn/zipball/17a5935eab1b89fb4b95600db50a1b6d5faa6cea", - "reference": "17a5935eab1b89fb4b95600db50a1b6d5faa6cea", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", "shasum": "" }, "require": { - "php": ">=8.0" - }, - "require-dev": { - "laravel/pint": "1.2.*", - "phpunit/phpunit": "^9.3", - "squizlabs/php_codesniffer": "^3.6", - "vimeo/psalm": "4.0.1" + "php": ">=7.3" }, "type": "library", - "autoload": { - "psr-4": { - "Utopia\\DSN\\": "src/DSN" + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], - "description": "A simple library for parsing and managing Data Source Names ( DSNs )", - "keywords": [ - "dsn", - "framework", - "php", - "upf", - "utopia" + "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", "support": { - "issues": "https://github.com/utopia-php/dsn/issues", - "source": "https://github.com/utopia-php/dsn/tree/0.1.0" + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" }, - "time": "2022-10-26T10:06:20+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" }, { - "name": "utopia-php/framework", - "version": "dev-fix-v2-swoole-coroutines", + "name": "swoole/ide-helper", + "version": "4.8.5", "source": { "type": "git", - "url": "https://github.com/utopia-php/framework.git", - "reference": "c68f74e633edfdc71c42d175c0505427d00848b7" + "url": "https://github.com/swoole/ide-helper.git", + "reference": "d03c707d4dc803228e93b4884c72949c4d28e8b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/c68f74e633edfdc71c42d175c0505427d00848b7", - "reference": "c68f74e633edfdc71c42d175c0505427d00848b7", + "url": "https://api.github.com/repos/swoole/ide-helper/zipball/d03c707d4dc803228e93b4884c72949c4d28e8b8", + "reference": "d03c707d4dc803228e93b4884c72949c4d28e8b8", "shasum": "" }, - "require": { - "ext-swoole": "*", - "php": ">=8.0" - }, - "require-dev": { - "laravel/pint": "^1.2", - "phpbench/phpbench": "^1.2", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^9.5.25", - "swoole/ide-helper": "4.8.3" - }, "type": "library", - "autoload": { - "psr-4": { - "Utopia\\Http\\": "src/Http" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "Apache-2.0" ], - "description": "A simple, light and advanced PHP framework", - "keywords": [ - "framework", - "php", - "upf" + "authors": [ + { + "name": "Team Swoole", + "email": "team@swoole.com" + } ], + "description": "IDE help files for Swoole.", "support": { - "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/fix-v2-swoole-coroutines" + "issues": "https://github.com/swoole/ide-helper/issues", + "source": "https://github.com/swoole/ide-helper/tree/4.8.5" }, - "time": "2023-10-11T08:46:00+00:00" + "funding": [ + { + "url": "https://gitee.com/swoole/swoole?donate=true", + "type": "custom" + }, + { + "url": "https://github.com/swoole", + "type": "github" + } + ], + "time": "2021-12-24T22:44:20+00:00" }, { - "name": "utopia-php/mongo", - "version": "0.3.1", + "name": "theseer/tokenizer", + "version": "1.2.1", "source": { "type": "git", - "url": "https://github.com/utopia-php/mongo.git", - "reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee" + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/mongo/zipball/52326a9a43e2d27ff0c15c48ba746dacbe9a7aee", - "reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "shasum": "" }, "require": { - "ext-mongodb": "*", - "mongodb/mongodb": "1.10.0", - "php": ">=8.0" - }, - "require-dev": { - "fakerphp/faker": "^1.14", - "laravel/pint": "1.2.*", - "phpstan/phpstan": "1.8.*", - "phpunit/phpunit": "^9.4", - "swoole/ide-helper": "4.8.0" + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { - "psr-4": { - "Utopia\\Mongo\\": "src" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Eldad Fux", - "email": "eldad@appwrite.io" - }, - { - "name": "Wess", - "email": "wess@appwrite.io" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" } ], - "description": "A simple library to manage Mongo database", - "keywords": [ - "database", - "mongo", - "php", - "upf", - "utopia" - ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { - "issues": "https://github.com/utopia-php/mongo/issues", - "source": "https://github.com/utopia-php/mongo/tree/0.3.1" + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" }, - "time": "2023-09-01T17:25:28+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" }, { - "name": "utopia-php/registry", - "version": "0.6.0", + "name": "utopia-php/fetch", + "version": "0.1.0", "source": { "type": "git", - "url": "https://github.com/utopia-php/registry.git", - "reference": "9c183312e48c926135085f34ac2e73dadb83e0c8" + "url": "https://github.com/utopia-php/fetch.git", + "reference": "2fa214b9262acd1a3583515a364da4f35929d5c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/registry/zipball/9c183312e48c926135085f34ac2e73dadb83e0c8", - "reference": "9c183312e48c926135085f34ac2e73dadb83e0c8", + "url": "https://api.github.com/repos/utopia-php/fetch/zipball/2fa214b9262acd1a3583515a364da4f35929d5c5", + "reference": "2fa214b9262acd1a3583515a364da4f35929d5c5", "shasum": "" }, "require": { - "php": ">=7.4" + "php": ">=8.0" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "vimeo/psalm": "4.0.1" + "laravel/pint": "^1.5.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5" }, "type": "library", "autoload": { "psr-4": { - "Utopia\\Registry\\": "src/Registry" + "Utopia\\Fetch\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Eldad Fux", - "email": "eldad@appwrite.io" - } - ], - "description": "A simple dependency management library for PHP", - "keywords": [ - "dependency management", - "di", - "framework", - "php", - "upf", - "utopia" - ], + "description": "A simple library that provides an interface for making HTTP Requests.", "support": { - "issues": "https://github.com/utopia-php/registry/issues", - "source": "https://github.com/utopia-php/registry/tree/0.6.0" + "issues": "https://github.com/utopia-php/fetch/issues", + "source": "https://github.com/utopia-php/fetch/tree/0.1.0" }, - "time": "2022-07-17T15:26:57+00:00" + "time": "2023-10-10T11:58:32+00:00" } ], "aliases": [ diff --git a/docker-compose.yml b/docker-compose.yml index 3af1cc0..c30ed3d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,14 +13,19 @@ services: ports: - 8088:80 environment: + - UTOPIA_DATABASE_PROXY_ENV - UTOPIA_DATABASE_PROXY_SECRET - UTOPIA_DATABASE_PROXY_SECRET_CONNECTIONS + - UTOPIA_DATABASE_PROXY_LOGGING_PROVIDER + - UTOPIA_DATABASE_PROXY_LOGGING_CONFIG mariadb: image: mariadb:10.7 container_name: utopia-mariadb networks: - database + ports: + - 8100:3306 environment: - MYSQL_ROOT_PASSWORD=password - MARIADB_DATABASE=appwrite diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..178b25a --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,16 @@ + + + + ./tests/ + + + diff --git a/pint.json b/pint.json index c781933..70add70 100644 --- a/pint.json +++ b/pint.json @@ -1,3 +1,6 @@ { - "preset": "psr12" + "preset": "psr12", + "exclude": [ + "tests/resources" + ] } \ No newline at end of file diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php new file mode 100644 index 0000000..ab779b9 --- /dev/null +++ b/tests/ProxyTest.php @@ -0,0 +1,177 @@ +namespace .= '-' . \uniqid(); + } + + private function call(string $method, string $endpoint, mixed $body = [], array $roles = [], bool $skipAuth = false): Response + { + return Client::fetch($this->endpoint . $endpoint, [ + 'x-utopia-secret' => $this->secret, + 'x-utopia-database' => $this->database, + 'x-utopia-namespace' => $this->namespace, + 'x-utopia-default-database' => $this->defaultDatabase, + 'x-utopia-auth-roles' => \implode(',', $roles), + 'x-utopia-auth-status' => $skipAuth ? 'false' : 'true', + 'x-utopia-auth-status-default' => $this->defaultAuthStatus ? 'true' : false, + 'x-utopia-timeout' => $this->timeout, + 'content-type' => 'application/json' + ], $method, $body); + } + + public function testSecret(): void + { + $correctSecret = $this->secret; + $this->secret = 'wrong-secret'; + $response = $this->call('GET', 'ping'); + self::assertEquals(401, $response->getStatusCode()); + $this->secret = $correctSecret; + } + + public function testDatabase(): void + { + $correctDatabase = $this->database; + $this->database = 'wrong-database'; + $response = $this->call('ping'); + self::assertEquals(400, $response->getStatusCode()); + $this->database = $correctDatabase; + } + + public function testDefaultDatabase(): void + { + $response = $this->call('exists', [ + 'database' => 'wrong-default-database', + ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertFalse($body['output']); + + $correctDefaultDatabase = $this->defaultDatabase; + $this->defaultDatabase = 'wrong-default-database'; + $response = $this->call('createCollection', [ + 'name' => 'defaultDbTest', + 'attributes' => [], + 'indexes' => [] + ]); + + $response = $this->call('exists', [ + 'database' => 'wrong-default-database', + ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertFalse($body['output']); + + $response = $this->call('exists', [ + 'database' => 'wrong-default-database', + 'collection' => 'defaultDbTest' + ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertFalse($body['output']); + + $this->defaultDatabase = $correctDefaultDatabase; + } + + public function testNamespace(): void + { + $correctNamespace = $this->namespace; + $this->namespace = $this->namespace . '-wrong'; + + $response = $this->call('exists', [ 'database' => $this->defaultDatabase, 'collection' => 'cars' ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertFalse($body['output']); + + $response = $this->call('createCollection', [ + 'name' => 'cars', + 'attributes' => [], + 'indexes' => [] + ]); + + $response = $this->call('exists', [ 'database' => $this->defaultDatabase, 'collection' => 'cars' ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertTrue($body['output']); + + $this->namespace = $correctNamespace; + + $response = $this->call('exists', [ 'database' => $this->defaultDatabase, 'collection' => 'cars' ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertFalse($body['output']); + } + + public function testMock(): void + { + $correctEndpoint = $this->endpoint; + $this->endpoint = 'http://tests/mock/'; + $response = $this->call('error'); + self::assertEquals(500, $response->getStatusCode()); + $this->endpoint = $correctEndpoint; + } + + public function testPing(): void + { + $response = $this->call('ping'); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertTrue($body['output']); + } + + public function testExists(): void + { + $response = $this->call('exists'); + self::assertEquals(400, $response->getStatusCode()); + + $response = $this->call('exists', [ 'collection' => 'books' ]); + self::assertEquals(400, $response->getStatusCode()); + + $response = $this->call('exists', [ 'database' => 'wrong-database' ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertFalse($body['output']); + + $response = $this->call('exists', [ 'database' => $this->defaultDatabase ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertTrue($body['output']); + + $response = $this->call('exists', [ 'database' => $this->defaultDatabase, 'collection' => 'books' ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertFalse($body['output']); + + $response = $this->call('createCollection', [ + 'name' => 'books', + 'attributes' => [], + 'indexes' => [] + ]); + + $response = $this->call('exists', [ 'database' => $this->defaultDatabase, 'collection' => 'books' ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertTrue($body['output']); + } + + // TODO: Test for every endpoint + // TODO: Timeout test + // TODO: Roles test + // TODO: Auth Status test +} \ No newline at end of file From 496ff766edecd9cafc8d0a5c8c2dd8e066c9a14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 18 Oct 2023 12:51:38 +0200 Subject: [PATCH 05/32] Rename endpoints, add pool --- .env | 2 +- app/endpoints.php | 161 +++++++++++++++++++---------------- app/http.php | 101 ++++++++++++---------- composer.json | 3 +- composer.lock | 53 +++++++++++- docker-compose.yml | 4 +- mariadb.cnf | 2 + tests/ProxyTest.php | 115 ++++++++++++++----------- tests/benchmark/benchmark.sh | 3 + tests/benchmark/k6.js | 13 +++ 10 files changed, 282 insertions(+), 175 deletions(-) create mode 100644 mariadb.cnf create mode 100644 tests/benchmark/benchmark.sh create mode 100644 tests/benchmark/k6.js diff --git a/.env b/.env index 8de49d9..a3b8212 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ UTOPIA_DATABASE_PROXY_ENV=development UTOPIA_DATABASE_PROXY_SECRET=proxy-secret-key -UTOPIA_DATABASE_PROXY_SECRET_CONNECTIONS=default=mariadb://root:password@mariadb:3306/appwrite +UTOPIA_DATABASE_PROXY_SECRET_CONNECTION=mariadb://root:password@mariadb:3306/appwrite?pool_size=256 UTOPIA_DATABASE_PROXY_LOGGING_PROVIDER= UTOPIA_DATABASE_PROXY_LOGGING_CONFIG= \ No newline at end of file diff --git a/app/endpoints.php b/app/endpoints.php index 0a06abd..82e2c39 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -13,13 +13,13 @@ use Utopia\Http\Validator\Integer; use Utopia\Http\Validator\Text; -Http::post('/mock/error') - ->groups(['api']) +Http::get('/mock/error') + ->groups(['api', 'mock']) ->action(function () { throw new Exception('Mock error', 500); }); -Http::post('/v1/queries/ping') +Http::get('/v1/ping') ->groups(['api']) ->inject('adapter') ->inject('response') @@ -31,13 +31,26 @@ ]); }); -Http::post('/v1/queries/exists') +Http::get('/v1/databases/:database') ->groups(['api']) ->param('database', '', new Text(MAX_STRING_SIZE, 0)) - ->param('collection', null, new Text(MAX_STRING_SIZE, 0), '', true) ->inject('adapter') ->inject('response') - ->action(function (string $database, ?string $collection, Adapter $adapter, Response $response) { + ->action(function (string $database, Adapter $adapter, Response $response) { + $output = $adapter->exists($database, null); + + $response->json([ + 'output' => $output + ]); + }); + +Http::get('/v1/collections/:collection') + ->groups(['api']) + ->param('database', '', new Text(MAX_STRING_SIZE, 0)) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) + ->inject('adapter') + ->inject('response') + ->action(function (string $database, string $collection, Adapter $adapter, Response $response) { $output = $adapter->exists($database, $collection); $response->json([ @@ -45,40 +58,40 @@ ]); }); -Http::post('/v1/queries/create') +Http::post('/v1/databases') ->groups(['api']) - ->param('name', '', new Text(MAX_STRING_SIZE, 0)) + ->param('database', '', new Text(MAX_STRING_SIZE, 0)) ->inject('adapter') ->inject('response') - ->action(function (string $name, Adapter $adapter, Response $response) { - $output = $adapter->create($name); + ->action(function (string $database, Adapter $adapter, Response $response) { + $output = $adapter->create($database); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/delete') +Http::delete('/v1/databases/:database') ->groups(['api']) - ->param('name', '', new Text(MAX_STRING_SIZE, 0)) + ->param('database', '', new Text(MAX_STRING_SIZE, 0)) ->inject('adapter') ->inject('response') - ->action(function (string $name, Adapter $adapter, Response $response) { - $output = $adapter->delete($name); + ->action(function (string $database, Adapter $adapter, Response $response) { + $output = $adapter->delete($database); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/createCollection') +Http::post('/v1/collections') ->groups(['api']) - ->param('name', '', new Text(MAX_STRING_SIZE, 0)) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('attributes', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) ->param('indexes', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) ->inject('adapter') ->inject('response') - ->action(function (string $name, array $attributes, array $indexes, Adapter $adapter, Response $response) { + ->action(function (string $collection, array $attributes, array $indexes, Adapter $adapter, Response $response) { foreach ($attributes as &$attribute) { $attribute = new Document($attribute); } @@ -87,139 +100,139 @@ $index = new Document($index); } - $output = $adapter->createCollection($name, $attributes, $indexes); + $output = $adapter->createCollection($collection, $attributes, $indexes); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/deleteCollection') +Http::delete('/v1/collections/:collection') ->groups(['api']) - ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->inject('adapter') ->inject('response') - ->action(function (string $id, Adapter $adapter, Response $response) { - $output = $adapter->deleteCollection($id); + ->action(function (string $collection, Adapter $adapter, Response $response) { + $output = $adapter->deleteCollection($collection); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/createAttribute') +Http::post('/v1/collections/:collection/attributes') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) ->param('type', '', new Text(MAX_STRING_SIZE, 0)) ->param('size', '', new Integer()) ->param('signed', true, new Boolean(), '', true) ->param('array', false, new Boolean(), '', true) ->inject('adapter') ->inject('response') - ->action(function (string $collection, string $id, string $type, int $size, bool $signed, bool $array, Adapter $adapter, Response $response) { - $output = $adapter->createAttribute($collection, $id, $type, $size, $signed, $array); + ->action(function (string $collection, string $attribute, string $type, int $size, bool $signed, bool $array, Adapter $adapter, Response $response) { + $output = $adapter->createAttribute($collection, $attribute, $type, $size, $signed, $array); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/updateAttribute') +Http::put('/v1/collections/:collection/attributes/:attribute') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) ->param('type', '', new Text(MAX_STRING_SIZE, 0)) ->param('size', '', new Integer()) ->param('signed', true, new Boolean(), '', true) ->param('array', false, new Boolean(), '', true) ->inject('adapter') ->inject('response') - ->action(function (string $collection, string $id, string $type, int $size, bool $signed, bool $array, Adapter $adapter, Response $response) { - $output = $adapter->updateAttribute($collection, $id, $type, $size, $signed, $array); + ->action(function (string $collection, string $attribute, string $type, int $size, bool $signed, bool $array, Adapter $adapter, Response $response) { + $output = $adapter->updateAttribute($collection, $attribute, $type, $size, $signed, $array); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/deleteAttribute') +Http::delete('/v1/collections/:collection/attributes/:attribute') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) ->inject('adapter') ->inject('response') - ->action(function (string $collection, string $id, Adapter $adapter, Response $response) { - $output = $adapter->deleteAttribute($collection, $id); + ->action(function (string $collection, string $attribute, Adapter $adapter, Response $response) { + $output = $adapter->deleteAttribute($collection, $attribute); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/renameAttribute') +Http::patch('/v1/collections/:collection/attributes/:attribute/name') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('old', '', new Text(MAX_STRING_SIZE, 0)) + ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) ->param('new', '', new Text(MAX_STRING_SIZE, 0)) ->inject('adapter') ->inject('response') - ->action(function (string $collection, string $old, string $new, Adapter $adapter, Response $response) { - $output = $adapter->renameAttribute($collection, $old, $new); + ->action(function (string $collection, string $attribute, string $new, Adapter $adapter, Response $response) { + $output = $adapter->renameAttribute($collection, $attribute, $new); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/createIndex') +Http::post('/v1/collections/:collection/indexes') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('index', '', new Text(MAX_STRING_SIZE, 0)) ->param('type', '', new Text(MAX_STRING_SIZE, 0)) ->param('attributes', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE)) ->param('lengths', [], new ArrayList(new Integer(), MAX_ARRAY_SIZE)) ->param('orders', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE)) ->inject('adapter') ->inject('response') - ->action(function (string $collection, string $id, string $type, array $attributes, array $lengths, array $orders, Adapter $adapter, Response $response) { - $output = $adapter->createIndex($collection, $id, $type, $attributes, $lengths, $orders); + ->action(function (string $collection, string $index, string $type, array $attributes, array $lengths, array $orders, Adapter $adapter, Response $response) { + $output = $adapter->createIndex($collection, $index, $type, $attributes, $lengths, $orders); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/renameIndex') +Http::patch('/v1/collections/:collection/indexes/:index/name') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('old', '', new Text(MAX_STRING_SIZE, 0)) + ->param('index', '', new Text(MAX_STRING_SIZE, 0)) ->param('new', '', new Text(MAX_STRING_SIZE, 0)) ->inject('adapter') ->inject('response') - ->action(function (string $collection, string $old, string $new, Adapter $adapter, Response $response) { - $output = $adapter->renameIndex($collection, $old, $new); + ->action(function (string $collection, string $index, string $new, Adapter $adapter, Response $response) { + $output = $adapter->renameIndex($collection, $index, $new); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/deleteIndex') +Http::delete('/v1/collections/:collection/indexes/:index') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('index', '', new Text(MAX_STRING_SIZE, 0)) ->inject('adapter') ->inject('response') - ->action(function (string $collection, string $id, Adapter $adapter, Response $response) { - $output = $adapter->deleteIndex($collection, $id); + ->action(function (string $collection, string $index, Adapter $adapter, Response $response) { + $output = $adapter->deleteIndex($collection, $index); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/getSizeOfCollection') +Http::get('/v1/collections/:collection/size') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->inject('adapter') @@ -233,7 +246,7 @@ }); -Http::post('/v1/queries/getCountOfAttributes') +Http::get('/v1/collections/:collection/counts/attributes') ->groups(['api']) ->param('collection', '', new Assoc(MAX_STRING_SIZE)) ->inject('adapter') @@ -248,7 +261,7 @@ ]); }); -Http::post('/v1/queries/getCountOfIndexes') +Http::get('/v1/collections/:collection/counts/indexes') ->groups(['api']) ->param('collection', '', new Assoc(MAX_STRING_SIZE)) ->inject('adapter') @@ -263,7 +276,7 @@ ]); }); -Http::post('/v1/queries/getAttributeWidth') +Http::get('/v1/collections/:collection/widths/attributes') ->groups(['api']) ->param('collection', '', new Assoc(MAX_STRING_SIZE)) ->inject('adapter') @@ -278,7 +291,7 @@ ]); }); -Http::post('/v1/queries/createDocument') +Http::post('/v1/collections/:collection/documents') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('document', '', new Assoc(MAX_STRING_SIZE)) @@ -294,7 +307,7 @@ ]); }); -Http::post('/v1/queries/updateDocument') +Http::put('/v1/collections/:collection/documents') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('document', '', new Assoc(MAX_STRING_SIZE)) @@ -310,40 +323,40 @@ ]); }); -Http::post('/v1/queries/deleteDocument') +Http::delete('/v1/collections/:collection/documents/:document') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('document', '', new Text(MAX_STRING_SIZE, 0)) ->inject('adapter') ->inject('response') - ->action(function (string $collection, string $id, Adapter $adapter, Response $response) { - $output = $adapter->deleteDocument($collection, $id); + ->action(function (string $collection, string $document, Adapter $adapter, Response $response) { + $output = $adapter->deleteDocument($collection, $document); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/getDocument') +Http::get('/v1/collections/:collection/documents/:document') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('document', '', new Text(MAX_STRING_SIZE, 0)) ->param('queries', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) ->inject('adapter') ->inject('response') - ->action(function (string $collection, string $id, array $queries, Adapter $adapter, Response $response) { + ->action(function (string $collection, string $document, array $queries, Adapter $adapter, Response $response) { foreach ($queries as &$query) { $query = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); } - $output = $adapter->getDocument($collection, $id, $queries); + $output = $adapter->getDocument($collection, $document, $queries); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/find') +Http::get('/v1/collections/:collection/documents') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('queries', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) @@ -368,7 +381,7 @@ ]); }); -Http::post('/v1/queries/sum') +Http::get('/v1/collections/:collection/documents-sum') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) @@ -389,7 +402,7 @@ ]); }); -Http::post('/v1/queries/count') +Http::get('/v1/collections/:collection/documents-count') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('queries', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) @@ -409,25 +422,25 @@ ]); }); -Http::post('/v1/queries/increaseDocumentAttribute') +Http::patch('/v1/collections/:collection/documents/:document/increase') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('id', '', new Text(MAX_STRING_SIZE, 0)) + ->param('document', '', new Text(MAX_STRING_SIZE, 0)) ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) ->param('value', null, new FloatValidator(), '', true) ->param('min', null, new FloatValidator(), '', true) ->param('max', null, new FloatValidator(), '', true) ->inject('adapter') ->inject('response') - ->action(function (string $collection, string $id, string $attribute, float $value, ?float $min, ?float $max, Adapter $adapter, Response $response) { - $output = $adapter->increaseDocumentAttribute($collection, $id, $attribute, $value, $min, $max); + ->action(function (string $collection, string $document, string $attribute, float $value, ?float $min, ?float $max, Adapter $adapter, Response $response) { + $output = $adapter->increaseDocumentAttribute($collection, $document, $attribute, $value, $min, $max); $response->json([ 'output' => $output ]); }); -Http::post('/v1/queries/createRelationship') +Http::post('/v1/collections/:collection/relationships') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('relatedCollection', '', new Text(MAX_STRING_SIZE, 0)) @@ -445,7 +458,7 @@ ]); }); -Http::post('/v1/queries/updateRelationship') +Http::put('/v1/collections/:collection/relationships/:relatedCollection') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('relatedCollection', '', new Text(MAX_STRING_SIZE, 0)) @@ -465,7 +478,7 @@ ]); }); -Http::post('/v1/queries/deleteRelationship') +Http::delete('/v1/collections/:collection/relationships/:relatedCollection') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('relatedCollection', '', new Text(MAX_STRING_SIZE, 0)) diff --git a/app/http.php b/app/http.php index 6b04ffb..83150dd 100644 --- a/app/http.php +++ b/app/http.php @@ -17,6 +17,8 @@ use Utopia\Logger\Adapter\Sentry; use Utopia\Logger\Log; use Utopia\Logger\Logger; +use Utopia\Pools\Connection; +use Utopia\Pools\Pool; use Utopia\Registry\Registry; use function Swoole\Coroutine\run; @@ -51,43 +53,37 @@ return $logger; }); -$registry->set('adapters', function () { - $dsns = \explode(',', Http::getEnv('UTOPIA_DATABASE_PROXY_SECRET_CONNECTIONS', '') ?? ''); +$registry->set('pool', function () { + $dsnString = Http::getEnv('UTOPIA_DATABASE_PROXY_SECRET_CONNECTION', '') ?? ''; - $adapters = []; - - foreach ($dsns as $dsnPair) { - [$dsnName, $dsnString] = explode('=', $dsnPair); - $dsn = new DSN($dsnString); - $dsnHost = $dsn->getHost(); - $dsnPort = $dsn->getPort(); - $dsnUser = $dsn->getUser(); - $dsnPass = $dsn->getPassword(); - $dsnScheme = $dsn->getScheme(); - $dsnDatabase = $dsn->getPath() ?? ''; - - // TODO: Introduce pools with ?pool_size=64 + $dsn = new DSN($dsnString); + $dsnHost = $dsn->getHost(); + $dsnPort = $dsn->getPort(); + $dsnUser = $dsn->getUser(); + $dsnPass = $dsn->getPassword(); + $dsnScheme = $dsn->getScheme(); + $dsnDatabase = $dsn->getPath() ?? ''; + $poolSize = \intval($dsn->getParam('pool_size', '255')); + $pool = new Pool('adapter-pool', $poolSize, function () use ($dsnScheme, $dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { switch ($dsnScheme) { case 'mariadb': - $adapters[$dsnName] = function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { - $pdo = new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, array( - PDO::ATTR_TIMEOUT => 15, // Seconds - PDO::ATTR_PERSISTENT => false, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_ERRMODE => Http::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed - PDO::ATTR_EMULATE_PREPARES => true, - PDO::ATTR_STRINGIFY_FETCHES => true - )); - $adapter = new MariaDB($pdo); - $adapter->setDefaultDatabase($dsnDatabase); - return $adapter; - }; - break; + $pdo = new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, array( + PDO::ATTR_TIMEOUT => 15, // Seconds + PDO::ATTR_PERSISTENT => false, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_ERRMODE => Http::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed + PDO::ATTR_EMULATE_PREPARES => true, + PDO::ATTR_STRINGIFY_FETCHES => true + )); + $adapter = new MariaDB($pdo); + $adapter->setDefaultDatabase($dsnDatabase); + + return $adapter; }; - } + }); - return $adapters; + return $pool; }); $http = new Server("0.0.0.0", Http::getEnv('UTOPIA_DATABASE_PROXY_PORT', '80')); @@ -108,11 +104,15 @@ Http::setResource('registry', fn () => $registry); Http::setResource('logger', fn (Registry $registry) => $registry->get('logger'), ['registry']); -Http::setResource('adapters', fn (Registry $registry) => $registry->get('adapters'), ['registry']); +Http::setResource('pool', fn (Registry $registry) => $registry->get('pool'), ['registry']); Http::setResource('log', fn () => new Log()); -Http::setResource('adapter', function (Request $request, array $adapters) { - $database = $request->getHeader('x-utopia-database', ''); +Http::setResource('adapterConnection', function (Pool $pool) { + $connection = $pool->pop(); + return $connection; +}, ['pool']); + +Http::setResource('adapter', function (Request $request, Connection $adapterConnection) { $namespace = $request->getHeader('x-utopia-namespace', ''); $timeout = $request->getHeader('x-utopia-timeout', ''); $defaultDatabase = $request->getHeader('x-utopia-default-database', ''); @@ -120,17 +120,7 @@ $status = $request->getHeader('x-utopia-auth-status', ''); $statusDefault = $request->getHeader('x-utopia-auth-status-default', ''); - if (empty($database)) { - throw new Exception('Incorrect database in x-utopia-database header.', 400); - } - - $adapter = $adapters[$database] ?? null; - - if (empty($adapter)) { - throw new Exception('Incorrect database in x-utopia-database header.', 400); - } - - $resource = $adapter(); + $resource = $adapterConnection->getResource(); $resource->setNamespace($namespace); if (!empty($timeout)) { @@ -168,7 +158,7 @@ } return $resource; -}, ['request', 'adapters']); +}, ['request', 'adapterConnection']); Http::init() ->groups(['api']) @@ -182,6 +172,25 @@ } }); +Http::shutdown() + ->inject('utopia') + ->inject('context') + ->action(function (Http $app, string $context) { + $connection = $app->getResource('adapterConnection', $context); + + if (isset($connection)) { + $connection->reclaim(); + } + }); + +Http::init() + ->groups(['mock']) + ->action(function () { + if (!Http::isDevelopment()) { + throw new Exception('Mock endpoints are not implemented on production.', 501); + } + }); + function logError(Log $log, Throwable $error, string $action, Logger $logger = null, ?Route $route = null): void { Console::error('[Error] Type: ' . get_class($error)); diff --git a/composer.json b/composer.json index 2fe53e5..2584f72 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,8 @@ "utopia-php/cli": "0.16.*", "utopia-php/registry": "0.6.*", "utopia-php/dsn": "0.1.*", - "utopia-php/logger": "0.3.*" + "utopia-php/logger": "0.3.*", + "utopia-php/pools": "0.4.*" }, "require-dev": { "swoole/ide-helper": "4.8.5", diff --git a/composer.lock b/composer.lock index 7f77937..0fcca21 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "194f0f452f37dc2b1ddccdfb06f1f5be", + "content-hash": "09e01f3dbf80dc94a6ddfce361a807db", "packages": [ { "name": "jean85/pretty-package-versions", @@ -578,6 +578,57 @@ }, "time": "2023-09-01T17:25:28+00:00" }, + { + "name": "utopia-php/pools", + "version": "0.4.2", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/pools.git", + "reference": "d2870ab74b31b7f4027799f082e85122154f8bed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/pools/zipball/d2870ab74b31b7f4027799f082e85122154f8bed", + "reference": "d2870ab74b31b7f4027799f082e85122154f8bed", + "shasum": "" + }, + "require": { + "php": ">=8.0" + }, + "require-dev": { + "laravel/pint": "1.2.*", + "phpstan/phpstan": "1.8.*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Pools\\": "src/Pools" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Team Appwrite", + "email": "team@appwrite.io" + } + ], + "description": "A simple library to manage connection pools", + "keywords": [ + "framework", + "php", + "pools", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/pools/issues", + "source": "https://github.com/utopia-php/pools/tree/0.4.2" + }, + "time": "2022-11-22T07:55:45+00:00" + }, { "name": "utopia-php/registry", "version": "0.6.0", diff --git a/docker-compose.yml b/docker-compose.yml index c30ed3d..1aeece0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,7 +15,7 @@ services: environment: - UTOPIA_DATABASE_PROXY_ENV - UTOPIA_DATABASE_PROXY_SECRET - - UTOPIA_DATABASE_PROXY_SECRET_CONNECTIONS + - UTOPIA_DATABASE_PROXY_SECRET_CONNECTION - UTOPIA_DATABASE_PROXY_LOGGING_PROVIDER - UTOPIA_DATABASE_PROXY_LOGGING_CONFIG @@ -29,6 +29,8 @@ services: environment: - MYSQL_ROOT_PASSWORD=password - MARIADB_DATABASE=appwrite + volumes: + - ./mariadb.cnf:/etc/mysql/my.cnf networks: database: \ No newline at end of file diff --git a/mariadb.cnf b/mariadb.cnf new file mode 100644 index 0000000..15ec476 --- /dev/null +++ b/mariadb.cnf @@ -0,0 +1,2 @@ +[mysqld] +max_connections=500 \ No newline at end of file diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php index ab779b9..0cb4771 100644 --- a/tests/ProxyTest.php +++ b/tests/ProxyTest.php @@ -10,7 +10,6 @@ final class ProxyTest extends TestCase { protected string $endpoint = 'http://tests/v1'; protected string $secret = 'proxy-secret-key'; - protected string $database = 'default'; protected string $namespace = 'my-namespace'; protected string $defaultDatabase = 'appwrite'; protected bool $defaultAuthStatus = true; @@ -21,17 +20,19 @@ protected function setUp(): void $this->namespace .= '-' . \uniqid(); } + /** + * @param array $roles + */ private function call(string $method, string $endpoint, mixed $body = [], array $roles = [], bool $skipAuth = false): Response { return Client::fetch($this->endpoint . $endpoint, [ 'x-utopia-secret' => $this->secret, - 'x-utopia-database' => $this->database, 'x-utopia-namespace' => $this->namespace, 'x-utopia-default-database' => $this->defaultDatabase, 'x-utopia-auth-roles' => \implode(',', $roles), 'x-utopia-auth-status' => $skipAuth ? 'false' : 'true', - 'x-utopia-auth-status-default' => $this->defaultAuthStatus ? 'true' : false, - 'x-utopia-timeout' => $this->timeout, + 'x-utopia-auth-status-default' => $this->defaultAuthStatus ? 'true' : 'false', + 'x-utopia-timeout' => \strval($this->timeout), 'content-type' => 'application/json' ], $method, $body); } @@ -40,48 +41,33 @@ public function testSecret(): void { $correctSecret = $this->secret; $this->secret = 'wrong-secret'; - $response = $this->call('GET', 'ping'); + $response = $this->call('GET', '/ping'); self::assertEquals(401, $response->getStatusCode()); $this->secret = $correctSecret; } - public function testDatabase(): void - { - $correctDatabase = $this->database; - $this->database = 'wrong-database'; - $response = $this->call('ping'); - self::assertEquals(400, $response->getStatusCode()); - $this->database = $correctDatabase; - } - public function testDefaultDatabase(): void { - $response = $this->call('exists', [ - 'database' => 'wrong-default-database', - ]); + $response = $this->call('GET', '/databases/wrong-default-database'); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertFalse($body['output']); $correctDefaultDatabase = $this->defaultDatabase; $this->defaultDatabase = 'wrong-default-database'; - $response = $this->call('createCollection', [ - 'name' => 'defaultDbTest', + $response = $this->call('POST', '/collections', [ + 'collection' => 'default-db-test', 'attributes' => [], 'indexes' => [] ]); - $response = $this->call('exists', [ - 'database' => 'wrong-default-database', - ]); + $response = $this->call('GET', '/databases/wrong-default-database'); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertFalse($body['output']); - $response = $this->call('exists', [ - 'database' => 'wrong-default-database', - 'collection' => 'defaultDbTest' - ]); + $response = $this->call('GET', '/collections/default-db-test?database=wrong-default-database'); + self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertFalse($body['output']); @@ -94,42 +80,46 @@ public function testNamespace(): void $correctNamespace = $this->namespace; $this->namespace = $this->namespace . '-wrong'; - $response = $this->call('exists', [ 'database' => $this->defaultDatabase, 'collection' => 'cars' ]); + $response = $this->call('GET', '/collections/cars?database=' . $this->defaultDatabase); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertFalse($body['output']); - $response = $this->call('createCollection', [ - 'name' => 'cars', + $response = $this->call('POST', '/collections', [ + 'collection' => 'cars', 'attributes' => [], 'indexes' => [] ]); - - $response = $this->call('exists', [ 'database' => $this->defaultDatabase, 'collection' => 'cars' ]); + + $response = $this->call('GET', '/collections/cars?database=' . $this->defaultDatabase); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); $this->namespace = $correctNamespace; - $response = $this->call('exists', [ 'database' => $this->defaultDatabase, 'collection' => 'cars' ]); + $response = $this->call('GET', '/collections/cars?database=' . $this->defaultDatabase); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertFalse($body['output']); } + // TODO: Timeout test + // TODO: Roles test + // TODO: Auth Status test + public function testMock(): void { $correctEndpoint = $this->endpoint; - $this->endpoint = 'http://tests/mock/'; - $response = $this->call('error'); + $this->endpoint = 'http://tests/mock'; + $response = $this->call('GET', '/error'); self::assertEquals(500, $response->getStatusCode()); $this->endpoint = $correctEndpoint; } - + public function testPing(): void { - $response = $this->call('ping'); + $response = $this->call('GET', '/ping'); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); @@ -137,41 +127,64 @@ public function testPing(): void public function testExists(): void { - $response = $this->call('exists'); - self::assertEquals(400, $response->getStatusCode()); - - $response = $this->call('exists', [ 'collection' => 'books' ]); + $response = $this->call('GET', '/collections/books'); self::assertEquals(400, $response->getStatusCode()); - $response = $this->call('exists', [ 'database' => 'wrong-database' ]); + $response = $this->call('GET', '/databases/wrong-database'); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertFalse($body['output']); - $response = $this->call('exists', [ 'database' => $this->defaultDatabase ]); + + $response = $this->call('GET', '/databases/' . $this->defaultDatabase); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); - $response = $this->call('exists', [ 'database' => $this->defaultDatabase, 'collection' => 'books' ]); + $response = $this->call('GET', '/collections/books?database=' . $this->defaultDatabase); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertFalse($body['output']); - $response = $this->call('createCollection', [ - 'name' => 'books', + $response = $this->call('POST', '/collections', [ + 'collection' => 'books', 'attributes' => [], 'indexes' => [] ]); - $response = $this->call('exists', [ 'database' => $this->defaultDatabase, 'collection' => 'books' ]); + $response = $this->call('GET', '/collections/books?database=' . $this->defaultDatabase); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); } - // TODO: Test for every endpoint - // TODO: Timeout test - // TODO: Roles test - // TODO: Auth Status test -} \ No newline at end of file + /** + * TODO: Add tests for all endpoints: + * Http::post('/v1/databases') + * Http::delete('/v1/databases/:database') + * Http::post('/v1/collections') + * Http::delete('/v1/collections/:collection') + * Http::post('/v1/collections/:collection/attributes') + * Http::put('/v1/collections/:collection/attributes/:attribute') + * Http::delete('/v1/collections/:collection/attributes/:attribute') + * Http::patch('/v1/collections/:collection/attributes/:attribute/name') + * Http::post('/v1/collections/:collection/indexes') + * Http::patch('/v1/collections/:collection/indexes/:index/name') + * Http::delete('/v1/collections/:collection/indexes/:index') + * Http::get('/v1/collections/:collection/size') + * Http::get('/v1/collections/:collection/counts/attributes') + * Http::get('/v1/collections/:collection/counts/indexes') + * Http::get('/v1/collections/:collection/widths/attributes') + * Http::post('/v1/collections/:collection/documents') + * Http::put('/v1/collections/:collection/documents') + * Http::delete('/v1/collections/:collection/documents/:document') + * Http::get('/v1/collections/:collection/documents/:document') + * Http::get('/v1/collections/:collection/documents') + * Http::get('/v1/collections/:collection/documents-sum') + * Http::get('/v1/collections/:collection/documents-count') + * Http::patch('/v1/collections/:collection/documents/:document/increase') + * Http::post('/v1/collections/:collection/relationships') + * Http::put('/v1/collections/:collection/relationships/:relatedCollection') + * Http::delete('/v1/collections/:collection/relationships/:relatedCollection') + */ +} diff --git a/tests/benchmark/benchmark.sh b/tests/benchmark/benchmark.sh new file mode 100644 index 0000000..b9bdee9 --- /dev/null +++ b/tests/benchmark/benchmark.sh @@ -0,0 +1,3 @@ +# Operation: Ping +# Max pool size: 256 +k6 run --vus 256 --duration 15s k6.js diff --git a/tests/benchmark/k6.js b/tests/benchmark/k6.js new file mode 100644 index 0000000..eb34849 --- /dev/null +++ b/tests/benchmark/k6.js @@ -0,0 +1,13 @@ +import http from 'k6/http'; +import { check, sleep } from 'k6'; + +export default function () { + const res = http.get('http://localhost:8088/v1/ping', { + headers: { + 'x-utopia-secret': 'proxy-secret-key', + 'x-utopia-namespace': 'utopia', + 'x-utopia-default-database': 'appwrite' + } + }); + check(res, { 'status was 200': (r) => r.status == 200 }); +} \ No newline at end of file From 9a64f7613f63494e650b25cb9116adaee95a3bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 18 Oct 2023 14:44:14 +0200 Subject: [PATCH 06/32] Remove memory limit --- app/http.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/http.php b/app/http.php index 83150dd..ddc4f85 100644 --- a/app/http.php +++ b/app/http.php @@ -27,6 +27,9 @@ const MAX_STRING_SIZE = 20 * 1024 * 1024; // 20 MB const PAYLOAD_SIZE = 20 * 1024 * 1024; // 20MB +// Unlimited memory limit to handle as many coroutines/requests as possible +ini_set('memory_limit', '-1'); + require_once __DIR__ . '/endpoints.php'; Http::setMode((string) Http::getEnv('UTOPIA_DATABASE_PROXY_ENV', Http::MODE_TYPE_PRODUCTION)); From bd8c0c2c76857f94cd3ddebdbaf9e369eae21c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 19 Oct 2023 11:35:34 +0200 Subject: [PATCH 07/32] Improve tests --- app/http.php | 21 ++++---- tests/ProxyTest.php | 114 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 120 insertions(+), 15 deletions(-) diff --git a/app/http.php b/app/http.php index ddc4f85..f4e4a73 100644 --- a/app/http.php +++ b/app/http.php @@ -127,7 +127,7 @@ $resource->setNamespace($namespace); if (!empty($timeout)) { - $resource->setTimeout($timeout); + $resource->setTimeout(\intval($timeout)); } else { $resource->clearTimeout(); } @@ -138,25 +138,26 @@ $resource->setDefaultDatabase(''); } + // TODO: This wont work with coroutines Authorization::cleanRoles(); Authorization::setRole('any'); foreach (\explode(',', $roles) as $role) { Authorization::setRole($role); } - if (!empty($statusDefault)) { - if ($statusDefault === 'true') { - Authorization::setDefaultStatus(true); - } else { - Authorization::setDefaultStatus(false); - } + // TODO: This wont work with coroutines + if (!empty($statusDefault) && $statusDefault === 'false') { + Authorization::setDefaultStatus(false); + } else { + Authorization::setDefaultStatus(true); } + // TODO: This wont work with coroutines if (!empty($status)) { - if ($status === 'true') { - Authorization::enable(); - } else { + if ($status === 'false') { Authorization::disable(); + } else { + Authorization::enable(); } } diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php index 0cb4771..2bd83e9 100644 --- a/tests/ProxyTest.php +++ b/tests/ProxyTest.php @@ -3,6 +3,11 @@ namespace Tests; use PHPUnit\Framework\TestCase; +use Utopia\Database\Database; +use Utopia\Database\Document; +use Utopia\Database\Helpers\ID; +use Utopia\Database\Helpers\Permission; +use Utopia\Database\Helpers\Role; use Utopia\Fetch\Client; use Utopia\Fetch\Response; @@ -13,7 +18,7 @@ final class ProxyTest extends TestCase protected string $namespace = 'my-namespace'; protected string $defaultDatabase = 'appwrite'; protected bool $defaultAuthStatus = true; - protected int $timeout = 10; // Seconds + protected int $timeout = 10000; // Milliseconds protected function setUp(): void { @@ -60,6 +65,9 @@ public function testDefaultDatabase(): void 'attributes' => [], 'indexes' => [] ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertTrue($body['output']); $response = $this->call('GET', '/databases/wrong-default-database'); self::assertEquals(200, $response->getStatusCode()); @@ -90,6 +98,9 @@ public function testNamespace(): void 'attributes' => [], 'indexes' => [] ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertTrue($body['output']); $response = $this->call('GET', '/collections/cars?database=' . $this->defaultDatabase); self::assertEquals(200, $response->getStatusCode()); @@ -104,9 +115,97 @@ public function testNamespace(): void self::assertFalse($body['output']); } - // TODO: Timeout test - // TODO: Roles test - // TODO: Auth Status test + public function testTimeout(): void + { + $correctTimeout = $this->timeout; + + $this->timeout = 600000; + $response = $this->call('GET', '/ping'); + self::assertEquals(200, $response->getStatusCode()); + + $this->timeout = -1; + $response = $this->call('GET', '/ping'); + self::assertEquals(500, $response->getStatusCode()); + + $this->timeout = $correctTimeout; + } + + public function testAuth(): void + { + $response = $this->call('POST', '/collections', [ + 'collection' => 'passwords', + 'attributes' => [ + new Document([ + '$id' => 'password', + 'type' => Database::VAR_STRING, + 'size' => 512, + 'required' => true + ]) + ], + 'indexes' => [] + ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertTrue($body['output']); + + $response = $this->call('GET', '/collections/passwords?database=' . $this->defaultDatabase); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertTrue($body['output']); + + $docAny = ID::unique(); + $response = $this->call('POST', '/collections/passwords/documents', [ + 'document' => new Document([ + '$id' => $docAny, + '$permissions' => [ + Permission::read(Role::any()) + ], + 'password' => 'any-password' + ]) + ]); + self::assertEquals(200, $response->getStatusCode()); + + $docsGuests = ID::unique(); + $response = $this->call('POST', '/collections/passwords/documents', [ + 'document' => new Document([ + '$id' => $docsGuests, + '$permissions' => [ + Permission::read(Role::guests()) + ], + 'password' => 'guests-password' + ]) + ]); + self::assertEquals(200, $response->getStatusCode()); + + $docUsers = ID::unique(); + $response = $this->call('POST', '/collections/passwords/documents', [ + 'document' => new Document([ + '$id' => $docUsers, + '$permissions' => [ + Permission::read(Role::users()) + ], + 'password' => 'users-password' + ]) + ]); + self::assertEquals(200, $response->getStatusCode()); + + $docTeam = ID::unique(); + $response = $this->call('POST', '/collections/passwords/documents', [ + 'document' => new Document([ + '$id' => $docTeam, + '$permissions' => [ + Permission::read(Role::team('admin')) + ], + 'password' => 'team-password' + ]) + ]); + self::assertEquals(200, $response->getStatusCode()); + + $response = $this->call('GET', '/collections/passwords/documents', [], [], true); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertCount(4, $body['output']); + } public function testMock(): void { @@ -151,6 +250,9 @@ public function testExists(): void 'attributes' => [], 'indexes' => [] ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertTrue($body['output']); $response = $this->call('GET', '/collections/books?database=' . $this->defaultDatabase); self::assertEquals(200, $response->getStatusCode()); @@ -159,7 +261,9 @@ public function testExists(): void } /** - * TODO: Add tests for all endpoints: + * TODO: We do a lot of E2E testing in utopia/database adapter. + * But eventuelly, lets add tests here for all endpoints: + * * Http::post('/v1/databases') * Http::delete('/v1/databases/:database') * Http::post('/v1/collections') From 314638039b83f5e639b91f911ee86089c692f727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 19 Oct 2023 13:27:10 +0200 Subject: [PATCH 08/32] More auth roles tests --- tests/ProxyTest.php | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php index 2bd83e9..6eaaa0f 100644 --- a/tests/ProxyTest.php +++ b/tests/ProxyTest.php @@ -205,6 +205,36 @@ public function testAuth(): void self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertCount(4, $body['output']); + + + $response = $this->call('GET', '/collections/passwords/documents', [], [], false); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertCount(1, $body['output']); + + $response = $this->call('GET', '/collections/passwords/documents', [], [ + 'users' + ], false); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertCount(2, $body['output']); + + $response = $this->call('GET', '/collections/passwords/documents', [], [ + 'guests' + ], false); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertCount(2, $body['output']); + + $response = $this->call('GET', '/collections/passwords/documents', [], [ + 'users', + 'guests', + 'team:admin' + ], false); + + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertCount(4, $body['output']); } public function testMock(): void From 02a45e6a106c18fded318ebf14dc218a7a7b4a5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 20 Nov 2023 11:59:34 +0000 Subject: [PATCH 09/32] PR review changes --- Dockerfile | 17 +- app/http.php | 3 +- composer.json | 12 +- composer.lock | 664 ++++++++++++++++++--------------------------- docker-compose.yml | 3 +- mariadb.cnf | 2 - 6 files changed, 293 insertions(+), 408 deletions(-) delete mode 100644 mariadb.cnf diff --git a/Dockerfile b/Dockerfile index 5b1bec7..c585e35 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,8 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \ # Prepare generic compiler FROM php:8.0.18-cli-alpine3.15 as compile -ENV PHP_SWOOLE_VERSION=v4.8.10 +ENV PHP_SWOOLE_VERSION="v5.1.0" \ + PHP_MONGODB_VERSION="1.16.1" RUN \ apk add --no-cache --virtual .deps \ @@ -37,6 +38,16 @@ RUN \ make && make install && \ cd .. +# Mongodb Extension +FROM compile as mongodb +RUN \ + git clone --depth 1 --branch $PHP_MONGODB_VERSION https://github.com/mongodb/mongo-php-driver.git && \ + cd mongo-php-driver && \ + git submodule update --init && \ + phpize && \ + ./configure && \ + make && make install + # Proxy FROM php:8.0.18-cli-alpine3.15 as final @@ -56,7 +67,8 @@ RUN \ curl-dev \ && apk add --no-cache \ libstdc++ \ - && docker-php-ext-install sockets pdo_mysql \ + postgresql-dev \ + && docker-php-ext-install sockets pdo_mysql pdo_pgsql \ && apk del .deps \ && rm -rf /var/cache/apk/* @@ -68,6 +80,7 @@ COPY ./app /usr/local/app # Extensions and libraries COPY --from=composer /usr/local/src/vendor /usr/local/vendor COPY --from=swoole /usr/local/lib/php/extensions/no-debug-non-zts-20200930/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/ +COPY --from=mongodb /usr/local/lib/php/extensions/no-debug-non-zts-20200930/mongodb.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/ RUN echo extension=swoole.so >> /usr/local/etc/php/conf.d/swoole.ini diff --git a/app/http.php b/app/http.php index f4e4a73..b2b0c22 100644 --- a/app/http.php +++ b/app/http.php @@ -191,7 +191,7 @@ ->groups(['mock']) ->action(function () { if (!Http::isDevelopment()) { - throw new Exception('Mock endpoints are not implemented on production.', 501); + throw new Exception('Mock endpoints are not implemented on production.', 404); } }); @@ -252,6 +252,7 @@ function logError(Log $log, Throwable $error, string $action, Logger $logger = n case 403: // Error allowed publicly case 404: // Error allowed publicly case 406: // Error allowed publicly + case 408: // Error allowed publicly case 409: // Error allowed publicly case 412: // Error allowed publicly case 425: // Error allowed publicly diff --git a/composer.json b/composer.json index 2584f72..bb2eac4 100644 --- a/composer.json +++ b/composer.json @@ -14,8 +14,8 @@ } }, "scripts": { - "lint": "./vendor/bin/pint --preset psr12 --test", - "format": "./vendor/bin/pint --preset psr12", + "lint": "./vendor/bin/pint --test", + "format": "./vendor/bin/pint", "check": "./vendor/bin/phpstan analyse --level 8 -c phpstan.neon app tests", "test": "./vendor/bin/phpunit --configuration phpunit.xml --debug" }, @@ -34,10 +34,10 @@ "utopia-php/pools": "0.4.*" }, "require-dev": { - "swoole/ide-helper": "4.8.5", - "phpunit/phpunit": "^9.3", - "laravel/pint": "1.2.*", - "phpstan/phpstan": "1.8.*", + "swoole/ide-helper": "5.1.*", + "phpunit/phpunit": "10.4.*", + "laravel/pint": "1.13.*", + "phpstan/phpstan": "1.10.*", "utopia-php/fetch": "0.1.*" }, "config": { diff --git a/composer.lock b/composer.lock index 0fcca21..1f203ad 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "09e01f3dbf80dc94a6ddfce361a807db", + "content-hash": "91b31d8fc05141bf0fa35fc39d8bced9", "packages": [ { "name": "jean85/pretty-package-versions", @@ -683,88 +683,18 @@ } ], "packages-dev": [ - { - "name": "doctrine/instantiator", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "require-dev": { - "doctrine/coding-standard": "^11", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^1.2", - "phpstan/phpstan": "^1.9.4", - "phpstan/phpstan-phpunit": "^1.3", - "phpunit/phpunit": "^9.5.27", - "vimeo/psalm": "^5.4" - }, - "type": "library", - "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": "https://ocramius.github.io/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/2.0.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2022-12-30T00:23:10+00:00" - }, { "name": "laravel/pint", - "version": "v1.2.1", + "version": "v1.13.6", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1" + "reference": "3e3d2ab01c7d8b484c18e6100ecf53639c744fa7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/e60e2112ee779ce60f253695b273d1646a17d6f1", - "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1", + "url": "https://api.github.com/repos/laravel/pint/zipball/3e3d2ab01c7d8b484c18e6100ecf53639c744fa7", + "reference": "3e3d2ab01c7d8b484c18e6100ecf53639c744fa7", "shasum": "" }, "require": { @@ -772,16 +702,16 @@ "ext-mbstring": "*", "ext-tokenizer": "*", "ext-xml": "*", - "php": "^8.0" + "php": "^8.1.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.11.0", - "illuminate/view": "^9.32.0", - "laravel-zero/framework": "^9.2.0", - "mockery/mockery": "^1.5.1", - "nunomaduro/larastan": "^2.2.0", - "nunomaduro/termwind": "^1.14.0", - "pestphp/pest": "^1.22.1" + "friendsofphp/php-cs-fixer": "^3.38.0", + "illuminate/view": "^10.30.1", + "laravel-zero/framework": "^10.3.0", + "mockery/mockery": "^1.6.6", + "nunomaduro/larastan": "^2.6.4", + "nunomaduro/termwind": "^1.15.1", + "pestphp/pest": "^2.24.2" }, "bin": [ "builds/pint" @@ -817,7 +747,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2022-11-29T16:25:20+00:00" + "time": "2023-11-07T17:59:57+00:00" }, { "name": "myclabs/deep-copy", @@ -1047,16 +977,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.8.11", + "version": "1.10.43", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "46e223dd68a620da18855c23046ddb00940b4014" + "reference": "2c4129f6ca8c7cfa870098884b8869b410a5a361" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/46e223dd68a620da18855c23046ddb00940b4014", - "reference": "46e223dd68a620da18855c23046ddb00940b4014", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2c4129f6ca8c7cfa870098884b8869b410a5a361", + "reference": "2c4129f6ca8c7cfa870098884b8869b410a5a361", "shasum": "" }, "require": { @@ -1085,8 +1015,11 @@ "static analysis" ], "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.8.11" + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, "funding": [ { @@ -1102,20 +1035,20 @@ "type": "tidelift" } ], - "time": "2022-10-24T15:45:13+00:00" + "time": "2023-11-19T19:55:25+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.29", + "version": "10.1.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" + "reference": "84838eed9ded511f61dc3e8b5944a52d9017b297" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/84838eed9ded511f61dc3e8b5944a52d9017b297", + "reference": "84838eed9ded511f61dc3e8b5944a52d9017b297", "shasum": "" }, "require": { @@ -1123,18 +1056,18 @@ "ext-libxml": "*", "ext-xmlwriter": "*", "nikic/php-parser": "^4.15", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", + "php": ">=8.1", + "phpunit/php-file-iterator": "^4.0", + "phpunit/php-text-template": "^3.0", + "sebastian/code-unit-reverse-lookup": "^3.0", + "sebastian/complexity": "^3.0", + "sebastian/environment": "^6.0", + "sebastian/lines-of-code": "^2.0", + "sebastian/version": "^4.0", "theseer/tokenizer": "^1.2.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.1" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -1143,7 +1076,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "10.1-dev" } }, "autoload": { @@ -1172,7 +1105,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.8" }, "funding": [ { @@ -1180,32 +1113,32 @@ "type": "github" } ], - "time": "2023-09-19T04:57:46+00:00" + "time": "2023-11-15T13:31:15+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "3.0.6", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -1232,7 +1165,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" }, "funding": [ { @@ -1240,28 +1174,28 @@ "type": "github" } ], - "time": "2021-12-02T12:48:52+00:00" + "time": "2023-08-31T06:24:48+00:00" }, { "name": "phpunit/php-invoker", - "version": "3.1.1", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "suggest": { "ext-pcntl": "*" @@ -1269,7 +1203,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -1295,7 +1229,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" }, "funding": [ { @@ -1303,32 +1237,32 @@ "type": "github" } ], - "time": "2020-09-28T05:58:55+00:00" + "time": "2023-02-03T06:56:09+00:00" }, { "name": "phpunit/php-text-template", - "version": "2.0.4", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -1354,7 +1288,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" }, "funding": [ { @@ -1362,32 +1297,32 @@ "type": "github" } ], - "time": "2020-10-26T05:33:50+00:00" + "time": "2023-08-31T14:07:24+00:00" }, { "name": "phpunit/php-timer", - "version": "5.0.3", + "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -1413,7 +1348,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" }, "funding": [ { @@ -1421,24 +1356,23 @@ "type": "github" } ], - "time": "2020-10-26T13:16:10+00:00" + "time": "2023-02-03T06:57:52+00:00" }, { "name": "phpunit/phpunit", - "version": "9.6.13", + "version": "10.4.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" + "reference": "cacd8b9dd224efa8eb28beb69004126c7ca1a1a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/cacd8b9dd224efa8eb28beb69004126c7ca1a1a1", + "reference": "cacd8b9dd224efa8eb28beb69004126c7ca1a1a1", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", @@ -1448,27 +1382,26 @@ "myclabs/deep-copy": "^1.10.1", "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", - "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.28", - "phpunit/php-file-iterator": "^3.0.5", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", - "sebastian/version": "^3.0.2" + "php": ">=8.1", + "phpunit/php-code-coverage": "^10.1.5", + "phpunit/php-file-iterator": "^4.0", + "phpunit/php-invoker": "^4.0", + "phpunit/php-text-template": "^3.0", + "phpunit/php-timer": "^6.0", + "sebastian/cli-parser": "^2.0", + "sebastian/code-unit": "^2.0", + "sebastian/comparator": "^5.0", + "sebastian/diff": "^5.0", + "sebastian/environment": "^6.0", + "sebastian/exporter": "^5.1", + "sebastian/global-state": "^6.0.1", + "sebastian/object-enumerator": "^5.0", + "sebastian/recursion-context": "^5.0", + "sebastian/type": "^4.0", + "sebastian/version": "^4.0" }, "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + "ext-soap": "To be able to generate mocks based on WSDL files" }, "bin": [ "phpunit" @@ -1476,7 +1409,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.6-dev" + "dev-main": "10.4-dev" } }, "autoload": { @@ -1508,7 +1441,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.4.2" }, "funding": [ { @@ -1524,32 +1457,32 @@ "type": "tidelift" } ], - "time": "2023-09-19T05:39:22+00:00" + "time": "2023-10-26T07:21:45+00:00" }, { "name": "sebastian/cli-parser", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/efdc130dbbbb8ef0b545a994fd811725c5282cae", + "reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -1572,7 +1505,7 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.0" }, "funding": [ { @@ -1580,32 +1513,32 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2023-02-03T06:58:15+00:00" }, { "name": "sebastian/code-unit", - "version": "1.0.8", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -1628,7 +1561,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit", "support": { "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" }, "funding": [ { @@ -1636,32 +1569,32 @@ "type": "github" } ], - "time": "2020-10-26T13:08:54+00:00" + "time": "2023-02-03T06:58:43+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -1683,7 +1616,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" }, "funding": [ { @@ -1691,34 +1624,36 @@ "type": "github" } ], - "time": "2020-09-28T05:30:19+00:00" + "time": "2023-02-03T06:59:15+00:00" }, { "name": "sebastian/comparator", - "version": "4.0.8", + "version": "5.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + "reference": "2db5010a484d53ebf536087a70b4a5423c102372" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372", + "reference": "2db5010a484d53ebf536087a70b4a5423c102372", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/diff": "^5.0", + "sebastian/exporter": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -1757,7 +1692,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1" }, "funding": [ { @@ -1765,33 +1701,33 @@ "type": "github" } ], - "time": "2022-09-14T12:41:17+00:00" + "time": "2023-08-14T13:18:12+00:00" }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "68cfb347a44871f01e33ab0ef8215966432f6957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68cfb347a44871f01e33ab0ef8215966432f6957", + "reference": "68cfb347a44871f01e33ab0ef8215966432f6957", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", - "php": ">=7.3" + "nikic/php-parser": "^4.10", + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "3.1-dev" } }, "autoload": { @@ -1814,7 +1750,8 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/3.1.0" }, "funding": [ { @@ -1822,33 +1759,33 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2023-09-28T11:50:59+00:00" }, { "name": "sebastian/diff", - "version": "4.0.5", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/912dc2fbe3e3c1e7873313cc801b100b6c68c87b", + "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3", + "phpunit/phpunit": "^10.0", "symfony/process": "^4.2 || ^5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -1880,7 +1817,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/5.0.3" }, "funding": [ { @@ -1888,27 +1826,27 @@ "type": "github" } ], - "time": "2023-05-07T05:35:17+00:00" + "time": "2023-05-01T07:48:21+00:00" }, { "name": "sebastian/environment", - "version": "5.1.5", + "version": "6.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + "reference": "43c751b41d74f96cbbd4e07b7aec9675651e2951" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/43c751b41d74f96cbbd4e07b7aec9675651e2951", + "reference": "43c751b41d74f96cbbd4e07b7aec9675651e2951", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "suggest": { "ext-posix": "*" @@ -1916,7 +1854,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -1935,7 +1873,7 @@ } ], "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", + "homepage": "https://github.com/sebastianbergmann/environment", "keywords": [ "Xdebug", "environment", @@ -1943,7 +1881,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/6.0.1" }, "funding": [ { @@ -1951,34 +1890,34 @@ "type": "github" } ], - "time": "2023-02-03T06:03:51+00:00" + "time": "2023-04-11T05:39:26+00:00" }, { "name": "sebastian/exporter", - "version": "4.0.5", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + "reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/64f51654862e0f5e318db7e9dcc2292c63cdbddc", + "reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/recursion-context": "^5.0" }, "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -2020,7 +1959,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.1" }, "funding": [ { @@ -2028,38 +1968,35 @@ "type": "github" } ], - "time": "2022-09-14T06:03:37+00:00" + "time": "2023-09-24T13:22:09+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.6", + "version": "6.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bde739e7565280bda77be70044ac1047bc007e34" + "reference": "7ea9ead78f6d380d2a667864c132c2f7b83055e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", - "reference": "bde739e7565280bda77be70044ac1047bc007e34", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/7ea9ead78f6d380d2a667864c132c2f7b83055e4", + "reference": "7ea9ead78f6d380d2a667864c132c2f7b83055e4", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-uopz": "*" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-main": "6.0-dev" } }, "autoload": { @@ -2084,7 +2021,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.1" }, "funding": [ { @@ -2092,33 +2030,33 @@ "type": "github" } ], - "time": "2023-08-02T09:26:13+00:00" + "time": "2023-07-19T07:19:23+00:00" }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/649e40d279e243d985aa8fb6e74dd5bb28dc185d", + "reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", - "php": ">=7.3" + "nikic/php-parser": "^4.10", + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "2.0-dev" } }, "autoload": { @@ -2141,7 +2079,8 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.1" }, "funding": [ { @@ -2149,34 +2088,34 @@ "type": "github" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2023-08-31T09:25:50+00:00" }, { "name": "sebastian/object-enumerator", - "version": "4.0.4", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -2198,7 +2137,7 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" }, "funding": [ { @@ -2206,32 +2145,32 @@ "type": "github" } ], - "time": "2020-10-26T13:12:34+00:00" + "time": "2023-02-03T07:08:32+00:00" }, { "name": "sebastian/object-reflector", - "version": "2.0.4", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -2253,7 +2192,7 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" }, "funding": [ { @@ -2261,32 +2200,32 @@ "type": "github" } ], - "time": "2020-10-26T13:14:26+00:00" + "time": "2023-02-03T07:06:18+00:00" }, { "name": "sebastian/recursion-context", - "version": "4.0.5", + "version": "5.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + "reference": "05909fb5bc7df4c52992396d0116aed689f93712" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", + "reference": "05909fb5bc7df4c52992396d0116aed689f93712", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-main": "5.0-dev" } }, "autoload": { @@ -2316,62 +2255,7 @@ "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:07:39+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-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", - "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" }, "funding": [ { @@ -2379,32 +2263,32 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2023-02-03T07:05:40+00:00" }, { "name": "sebastian/type", - "version": "3.2.1", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.5" + "phpunit/phpunit": "^10.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -2427,7 +2311,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" }, "funding": [ { @@ -2435,29 +2319,29 @@ "type": "github" } ], - "time": "2023-02-03T06:13:03+00:00" + "time": "2023-02-03T07:10:45+00:00" }, { "name": "sebastian/version", - "version": "3.0.2", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "4.0-dev" } }, "autoload": { @@ -2480,7 +2364,7 @@ "homepage": "https://github.com/sebastianbergmann/version", "support": { "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" }, "funding": [ { @@ -2488,20 +2372,20 @@ "type": "github" } ], - "time": "2020-09-28T06:39:44+00:00" + "time": "2023-02-07T11:34:05+00:00" }, { "name": "swoole/ide-helper", - "version": "4.8.5", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/swoole/ide-helper.git", - "reference": "d03c707d4dc803228e93b4884c72949c4d28e8b8" + "reference": "07692fa8f1bb8eac828410acd613ea5877237b09" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swoole/ide-helper/zipball/d03c707d4dc803228e93b4884c72949c4d28e8b8", - "reference": "d03c707d4dc803228e93b4884c72949c4d28e8b8", + "url": "https://api.github.com/repos/swoole/ide-helper/zipball/07692fa8f1bb8eac828410acd613ea5877237b09", + "reference": "07692fa8f1bb8eac828410acd613ea5877237b09", "shasum": "" }, "type": "library", @@ -2518,32 +2402,22 @@ "description": "IDE help files for Swoole.", "support": { "issues": "https://github.com/swoole/ide-helper/issues", - "source": "https://github.com/swoole/ide-helper/tree/4.8.5" + "source": "https://github.com/swoole/ide-helper/tree/5.1.0" }, - "funding": [ - { - "url": "https://gitee.com/swoole/swoole?donate=true", - "type": "custom" - }, - { - "url": "https://github.com/swoole", - "type": "github" - } - ], - "time": "2021-12-24T22:44:20+00:00" + "time": "2023-10-05T04:52:59+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.1", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", "shasum": "" }, "require": { @@ -2572,7 +2446,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + "source": "https://github.com/theseer/tokenizer/tree/1.2.2" }, "funding": [ { @@ -2580,7 +2454,7 @@ "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" + "time": "2023-11-20T00:12:19+00:00" }, { "name": "utopia-php/fetch", @@ -2653,5 +2527,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/docker-compose.yml b/docker-compose.yml index 1aeece0..ae36d9d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,6 +22,7 @@ services: mariadb: image: mariadb:10.7 container_name: utopia-mariadb + command: 'mysqld --max_connections=500' networks: - database ports: @@ -29,8 +30,6 @@ services: environment: - MYSQL_ROOT_PASSWORD=password - MARIADB_DATABASE=appwrite - volumes: - - ./mariadb.cnf:/etc/mysql/my.cnf networks: database: \ No newline at end of file diff --git a/mariadb.cnf b/mariadb.cnf deleted file mode 100644 index 15ec476..0000000 --- a/mariadb.cnf +++ /dev/null @@ -1,2 +0,0 @@ -[mysqld] -max_connections=500 \ No newline at end of file From eeedcfcfd8eb4d05c286a781ed63581b63738248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 20 Nov 2023 13:26:33 +0000 Subject: [PATCH 10/32] PR review changes --- .github/workflows/tests.yml | 2 +- .gitignore | 2 +- .phpunit.result.cache | 1 + Dockerfile | 8 +- app/endpoints.php | 145 ++++++++---------------------------- composer.json | 6 +- phpunit.xml | 31 ++++---- 7 files changed, 55 insertions(+), 140 deletions(-) create mode 100644 .phpunit.result.cache diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2b780f0..df49a9b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,5 +29,5 @@ jobs: - name: Run Tests run: | - docker run --rm -v $PWD:/app --network database-proxy_database -w /app phpswoole/swoole:4.8.12-php8.0-alpine sh -c \ + docker run --rm -v $PWD:/app --network database-proxy_database -w /app phpswoole/swoole:4.8.12-php8.1-alpine sh -c \ "composer install --profile --ignore-platform-reqs && composer test" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 921bd61..03766f7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /vendor/ /.idea/ -.phpunit.result.cache \ No newline at end of file +.phpunit.cache \ No newline at end of file diff --git a/.phpunit.result.cache b/.phpunit.result.cache new file mode 100644 index 0000000..fd470f7 --- /dev/null +++ b/.phpunit.result.cache @@ -0,0 +1 @@ +{"version":1,"defects":{"Tests\\ProxyTest::testSecret":8,"Tests\\ProxyTest::testDefaultDatabase":7,"Tests\\ProxyTest::testNamespace":7,"Tests\\ProxyTest::testTimeout":7,"Tests\\ProxyTest::testAuth":7,"Tests\\ProxyTest::testMock":8,"Tests\\ProxyTest::testPing":7,"Tests\\ProxyTest::testExists":7},"times":{"Tests\\ProxyTest::testSecret":0.005,"Tests\\ProxyTest::testDefaultDatabase":0.009,"Tests\\ProxyTest::testNamespace":0.018,"Tests\\ProxyTest::testTimeout":0.005,"Tests\\ProxyTest::testAuth":0.056,"Tests\\ProxyTest::testMock":0.043,"Tests\\ProxyTest::testPing":0.003,"Tests\\ProxyTest::testExists":0.022}} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index c585e35..77dcfbf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \ --no-plugins --no-scripts --prefer-dist # Prepare generic compiler -FROM php:8.0.18-cli-alpine3.15 as compile +FROM php:8.1.25-cli-alpine3.16 as compile ENV PHP_SWOOLE_VERSION="v5.1.0" \ PHP_MONGODB_VERSION="1.16.1" @@ -49,7 +49,7 @@ RUN \ make && make install # Proxy -FROM php:8.0.18-cli-alpine3.15 as final +FROM php:8.1.25-cli-alpine3.16 as final ARG UTOPIA_DATABASE_PROXY_VERSION ENV UTOPIA_DATABASE_PROXY_VERSION=$UTOPIA_DATABASE_PROXY_VERSION @@ -79,8 +79,8 @@ COPY ./app /usr/local/app # Extensions and libraries COPY --from=composer /usr/local/src/vendor /usr/local/vendor -COPY --from=swoole /usr/local/lib/php/extensions/no-debug-non-zts-20200930/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/ -COPY --from=mongodb /usr/local/lib/php/extensions/no-debug-non-zts-20200930/mongodb.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/ +COPY --from=swoole /usr/local/lib/php/extensions/no-debug-non-zts-20210902/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/ +COPY --from=mongodb /usr/local/lib/php/extensions/no-debug-non-zts-20210902/mongodb.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/ RUN echo extension=swoole.so >> /usr/local/etc/php/conf.d/swoole.ini diff --git a/app/endpoints.php b/app/endpoints.php index 82e2c39..04efd05 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -25,10 +25,7 @@ ->inject('response') ->action(function (Adapter $adapter, Response $response) { $output = $adapter->ping(); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::get('/v1/databases/:database') @@ -38,10 +35,7 @@ ->inject('response') ->action(function (string $database, Adapter $adapter, Response $response) { $output = $adapter->exists($database, null); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::get('/v1/collections/:collection') @@ -52,10 +46,7 @@ ->inject('response') ->action(function (string $database, string $collection, Adapter $adapter, Response $response) { $output = $adapter->exists($database, $collection); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::post('/v1/databases') @@ -65,10 +56,7 @@ ->inject('response') ->action(function (string $database, Adapter $adapter, Response $response) { $output = $adapter->create($database); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::delete('/v1/databases/:database') @@ -78,10 +66,7 @@ ->inject('response') ->action(function (string $database, Adapter $adapter, Response $response) { $output = $adapter->delete($database); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::post('/v1/collections') @@ -101,10 +86,7 @@ } $output = $adapter->createCollection($collection, $attributes, $indexes); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::delete('/v1/collections/:collection') @@ -114,10 +96,7 @@ ->inject('response') ->action(function (string $collection, Adapter $adapter, Response $response) { $output = $adapter->deleteCollection($collection); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::post('/v1/collections/:collection/attributes') @@ -132,10 +111,7 @@ ->inject('response') ->action(function (string $collection, string $attribute, string $type, int $size, bool $signed, bool $array, Adapter $adapter, Response $response) { $output = $adapter->createAttribute($collection, $attribute, $type, $size, $signed, $array); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::put('/v1/collections/:collection/attributes/:attribute') @@ -150,10 +126,7 @@ ->inject('response') ->action(function (string $collection, string $attribute, string $type, int $size, bool $signed, bool $array, Adapter $adapter, Response $response) { $output = $adapter->updateAttribute($collection, $attribute, $type, $size, $signed, $array); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::delete('/v1/collections/:collection/attributes/:attribute') @@ -164,10 +137,7 @@ ->inject('response') ->action(function (string $collection, string $attribute, Adapter $adapter, Response $response) { $output = $adapter->deleteAttribute($collection, $attribute); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::patch('/v1/collections/:collection/attributes/:attribute/name') @@ -179,10 +149,7 @@ ->inject('response') ->action(function (string $collection, string $attribute, string $new, Adapter $adapter, Response $response) { $output = $adapter->renameAttribute($collection, $attribute, $new); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::post('/v1/collections/:collection/indexes') @@ -197,10 +164,7 @@ ->inject('response') ->action(function (string $collection, string $index, string $type, array $attributes, array $lengths, array $orders, Adapter $adapter, Response $response) { $output = $adapter->createIndex($collection, $index, $type, $attributes, $lengths, $orders); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::patch('/v1/collections/:collection/indexes/:index/name') @@ -212,10 +176,7 @@ ->inject('response') ->action(function (string $collection, string $index, string $new, Adapter $adapter, Response $response) { $output = $adapter->renameIndex($collection, $index, $new); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::delete('/v1/collections/:collection/indexes/:index') @@ -226,10 +187,7 @@ ->inject('response') ->action(function (string $collection, string $index, Adapter $adapter, Response $response) { $output = $adapter->deleteIndex($collection, $index); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::get('/v1/collections/:collection/size') @@ -239,10 +197,7 @@ ->inject('response') ->action(function (string $collection, Adapter $adapter, Response $response) { $output = $adapter->getSizeOfCollection($collection); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); @@ -255,10 +210,7 @@ $collection = new Document($collection); $output = $adapter->getCountOfAttributes($collection); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::get('/v1/collections/:collection/counts/indexes') @@ -270,10 +222,7 @@ $collection = new Document($collection); $output = $adapter->getCountOfIndexes($collection); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::get('/v1/collections/:collection/widths/attributes') @@ -285,10 +234,7 @@ $collection = new Document($collection); $output = $adapter->getAttributeWidth($collection); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::post('/v1/collections/:collection/documents') @@ -301,10 +247,7 @@ $document = new Document($document); $output = $adapter->createDocument($collection, $document); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::put('/v1/collections/:collection/documents') @@ -317,10 +260,7 @@ $document = new Document($document); $output = $adapter->updateDocument($collection, $document); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::delete('/v1/collections/:collection/documents/:document') @@ -331,10 +271,7 @@ ->inject('response') ->action(function (string $collection, string $document, Adapter $adapter, Response $response) { $output = $adapter->deleteDocument($collection, $document); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::get('/v1/collections/:collection/documents/:document') @@ -350,10 +287,7 @@ } $output = $adapter->getDocument($collection, $document, $queries); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::get('/v1/collections/:collection/documents') @@ -375,10 +309,7 @@ } $output = $adapter->find($collection, $queries, $limit, $offset, $orderAttributes, $orderTypes, $cursor, $cursorDirection, $timeout); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::get('/v1/collections/:collection/documents-sum') @@ -396,10 +327,7 @@ } $output = $adapter->sum($collection, $attribute, $queries, $max, $timeout); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::get('/v1/collections/:collection/documents-count') @@ -416,10 +344,7 @@ } $output = $adapter->count($collection, $queries, $max, $timeout); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::patch('/v1/collections/:collection/documents/:document/increase') @@ -434,10 +359,7 @@ ->inject('response') ->action(function (string $collection, string $document, string $attribute, float $value, ?float $min, ?float $max, Adapter $adapter, Response $response) { $output = $adapter->increaseDocumentAttribute($collection, $document, $attribute, $value, $min, $max); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::post('/v1/collections/:collection/relationships') @@ -452,10 +374,7 @@ ->inject('response') ->action(function (string $collection, string $relatedCollection, string $type, bool $twoWay, string $id, string $twoWayKey, Adapter $adapter, Response $response) { $output = $adapter->createRelationship($collection, $relatedCollection, $type, $twoWay, $id, $twoWayKey); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::put('/v1/collections/:collection/relationships/:relatedCollection') @@ -472,10 +391,7 @@ ->inject('response') ->action(function (string $collection, string $relatedCollection, string $type, bool $twoWay, string $key, string $twoWayKey, string $newKey, string $newTwoWayKey, Adapter $adapter, Response $response) { $output = $adapter->updateRelationship($collection, $relatedCollection, $type, $twoWay, $key, $twoWayKey, $newKey, $newTwoWayKey); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); Http::delete('/v1/collections/:collection/relationships/:relatedCollection') @@ -491,8 +407,5 @@ ->inject('response') ->action(function (string $collection, string $relatedCollection, string $type, bool $twoWay, string $key, string $twoWayKey, string $side, Adapter $adapter, Response $response) { $output = $adapter->deleteRelationship($collection, $relatedCollection, $type, $twoWay, $key, $twoWayKey, $side); - - $response->json([ - 'output' => $output - ]); + $response->json(['output' => $output]); }); diff --git a/composer.json b/composer.json index bb2eac4..bd2a421 100644 --- a/composer.json +++ b/composer.json @@ -17,10 +17,10 @@ "lint": "./vendor/bin/pint --test", "format": "./vendor/bin/pint", "check": "./vendor/bin/phpstan analyse --level 8 -c phpstan.neon app tests", - "test": "./vendor/bin/phpunit --configuration phpunit.xml --debug" + "test": "./vendor/bin/phpunit --configuration phpunit.xml --testdox" }, "require": { - "php": ">=8.0.0", + "php": ">=8.1.0", "ext-curl": "*", "ext-json": "*", "ext-swoole": "*", @@ -42,7 +42,7 @@ }, "config": { "platform": { - "php": "8.0" + "php": "8.1" } } } \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml index 178b25a..3b34652 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,16 +1,17 @@ - - - - ./tests/ - - + + + + + ./tests/ + + From 2b56bf9ec9bc1bacee2581106e45163eb2de91f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sat, 9 Dec 2023 08:37:00 +0000 Subject: [PATCH 11/32] Remove unnessessary endpoints --- app/endpoints.php | 25 ------------------------- tests/ProxyTest.php | 2 -- 2 files changed, 27 deletions(-) diff --git a/app/endpoints.php b/app/endpoints.php index 04efd05..ea5716b 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -200,31 +200,6 @@ $response->json(['output' => $output]); }); - -Http::get('/v1/collections/:collection/counts/attributes') - ->groups(['api']) - ->param('collection', '', new Assoc(MAX_STRING_SIZE)) - ->inject('adapter') - ->inject('response') - ->action(function (array $collection, Adapter $adapter, Response $response) { - $collection = new Document($collection); - - $output = $adapter->getCountOfAttributes($collection); - $response->json(['output' => $output]); - }); - -Http::get('/v1/collections/:collection/counts/indexes') - ->groups(['api']) - ->param('collection', '', new Assoc(MAX_STRING_SIZE)) - ->inject('adapter') - ->inject('response') - ->action(function (array $collection, Adapter $adapter, Response $response) { - $collection = new Document($collection); - - $output = $adapter->getCountOfIndexes($collection); - $response->json(['output' => $output]); - }); - Http::get('/v1/collections/:collection/widths/attributes') ->groups(['api']) ->param('collection', '', new Assoc(MAX_STRING_SIZE)) diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php index 6eaaa0f..49b3893 100644 --- a/tests/ProxyTest.php +++ b/tests/ProxyTest.php @@ -306,8 +306,6 @@ public function testExists(): void * Http::patch('/v1/collections/:collection/indexes/:index/name') * Http::delete('/v1/collections/:collection/indexes/:index') * Http::get('/v1/collections/:collection/size') - * Http::get('/v1/collections/:collection/counts/attributes') - * Http::get('/v1/collections/:collection/counts/indexes') * Http::get('/v1/collections/:collection/widths/attributes') * Http::post('/v1/collections/:collection/documents') * Http::put('/v1/collections/:collection/documents') From 2f54840eb7c115518f6bb8b3f78e14b087c40075 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sat, 9 Dec 2023 17:03:49 +0100 Subject: [PATCH 12/32] getDocument queries as string --- app/endpoints.php | 2 +- composer.lock | 62 +++++++++++++++++++++++------------------------ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/app/endpoints.php b/app/endpoints.php index 04efd05..904faa7 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -278,7 +278,7 @@ ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('document', '', new Text(MAX_STRING_SIZE, 0)) - ->param('queries', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) + ->param('queries', [], new ArrayList(new Text(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) ->inject('adapter') ->inject('response') ->action(function (string $collection, string $document, array $queries, Adapter $adapter, Response $response) { diff --git a/composer.lock b/composer.lock index 1f203ad..21b09da 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "91b31d8fc05141bf0fa35fc39d8bced9", + "content-hash": "c965011dcaabd16e1412e3630ae0686c", "packages": [ { "name": "jean85/pretty-package-versions", @@ -467,16 +467,16 @@ }, { "name": "utopia-php/logger", - "version": "0.3.1", + "version": "0.3.2", "source": { "type": "git", "url": "https://github.com/utopia-php/logger.git", - "reference": "de623f1ec1c672c795d113dd25c5bf212f7ef4fc" + "reference": "ba763c10688fe2ed715ad2bed3f13d18dfec6253" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/logger/zipball/de623f1ec1c672c795d113dd25c5bf212f7ef4fc", - "reference": "de623f1ec1c672c795d113dd25c5bf212f7ef4fc", + "url": "https://api.github.com/repos/utopia-php/logger/zipball/ba763c10688fe2ed715ad2bed3f13d18dfec6253", + "reference": "ba763c10688fe2ed715ad2bed3f13d18dfec6253", "shasum": "" }, "require": { @@ -514,9 +514,9 @@ ], "support": { "issues": "https://github.com/utopia-php/logger/issues", - "source": "https://github.com/utopia-php/logger/tree/0.3.1" + "source": "https://github.com/utopia-php/logger/tree/0.3.2" }, - "time": "2023-02-10T15:52:50+00:00" + "time": "2023-11-22T14:45:43+00:00" }, { "name": "utopia-php/mongo", @@ -685,16 +685,16 @@ "packages-dev": [ { "name": "laravel/pint", - "version": "v1.13.6", + "version": "v1.13.7", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "3e3d2ab01c7d8b484c18e6100ecf53639c744fa7" + "reference": "4157768980dbd977f1c4b4cc94997416d8b30ece" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/3e3d2ab01c7d8b484c18e6100ecf53639c744fa7", - "reference": "3e3d2ab01c7d8b484c18e6100ecf53639c744fa7", + "url": "https://api.github.com/repos/laravel/pint/zipball/4157768980dbd977f1c4b4cc94997416d8b30ece", + "reference": "4157768980dbd977f1c4b4cc94997416d8b30ece", "shasum": "" }, "require": { @@ -747,7 +747,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2023-11-07T17:59:57+00:00" + "time": "2023-12-05T19:43:12+00:00" }, { "name": "myclabs/deep-copy", @@ -977,16 +977,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.43", + "version": "1.10.48", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "2c4129f6ca8c7cfa870098884b8869b410a5a361" + "reference": "087ed4b5f4a7a6e8f3bbdfbfe98ce5c181380bc6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2c4129f6ca8c7cfa870098884b8869b410a5a361", - "reference": "2c4129f6ca8c7cfa870098884b8869b410a5a361", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/087ed4b5f4a7a6e8f3bbdfbfe98ce5c181380bc6", + "reference": "087ed4b5f4a7a6e8f3bbdfbfe98ce5c181380bc6", "shasum": "" }, "require": { @@ -1035,20 +1035,20 @@ "type": "tidelift" } ], - "time": "2023-11-19T19:55:25+00:00" + "time": "2023-12-08T14:34:28+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "10.1.8", + "version": "10.1.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "84838eed9ded511f61dc3e8b5944a52d9017b297" + "reference": "a56a9ab2f680246adcf3db43f38ddf1765774735" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/84838eed9ded511f61dc3e8b5944a52d9017b297", - "reference": "84838eed9ded511f61dc3e8b5944a52d9017b297", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/a56a9ab2f680246adcf3db43f38ddf1765774735", + "reference": "a56a9ab2f680246adcf3db43f38ddf1765774735", "shasum": "" }, "require": { @@ -1105,7 +1105,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.8" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.9" }, "funding": [ { @@ -1113,7 +1113,7 @@ "type": "github" } ], - "time": "2023-11-15T13:31:15+00:00" + "time": "2023-11-23T12:23:20+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2376,16 +2376,16 @@ }, { "name": "swoole/ide-helper", - "version": "5.1.0", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/swoole/ide-helper.git", - "reference": "07692fa8f1bb8eac828410acd613ea5877237b09" + "reference": "69b374d982e7139fc904cc61757e7fede1d9c3d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swoole/ide-helper/zipball/07692fa8f1bb8eac828410acd613ea5877237b09", - "reference": "07692fa8f1bb8eac828410acd613ea5877237b09", + "url": "https://api.github.com/repos/swoole/ide-helper/zipball/69b374d982e7139fc904cc61757e7fede1d9c3d8", + "reference": "69b374d982e7139fc904cc61757e7fede1d9c3d8", "shasum": "" }, "type": "library", @@ -2402,9 +2402,9 @@ "description": "IDE help files for Swoole.", "support": { "issues": "https://github.com/swoole/ide-helper/issues", - "source": "https://github.com/swoole/ide-helper/tree/5.1.0" + "source": "https://github.com/swoole/ide-helper/tree/5.1.1" }, - "time": "2023-10-05T04:52:59+00:00" + "time": "2023-12-08T17:56:23+00:00" }, { "name": "theseer/tokenizer", @@ -2518,14 +2518,14 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=8.0.0", + "php": ">=8.1.0", "ext-curl": "*", "ext-json": "*", "ext-swoole": "*" }, "platform-dev": [], "platform-overrides": { - "php": "8.0" + "php": "8.1" }, "plugin-api-version": "2.6.0" } From 6fa0086e48df54e68257404e51130567bf677896 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sat, 9 Dec 2023 17:22:56 +0100 Subject: [PATCH 13/32] json_encode queries --- app/endpoints.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/endpoints.php b/app/endpoints.php index 58bc97d..a092655 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -257,8 +257,9 @@ ->inject('adapter') ->inject('response') ->action(function (string $collection, string $document, array $queries, Adapter $adapter, Response $response) { - foreach ($queries as &$query) { - $query = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); + foreach ($queries as $index => $query) { + $query = json_encode($query); + $queries[$index] = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); } $output = $adapter->getDocument($collection, $document, $queries); From 0caa0a17bdab3743d4de9760a8a99164ba01c6ba Mon Sep 17 00:00:00 2001 From: fogelito Date: Sat, 9 Dec 2023 17:50:57 +0100 Subject: [PATCH 14/32] json_encode queries --- app/endpoints.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/endpoints.php b/app/endpoints.php index a092655..7aa016c 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -258,7 +258,7 @@ ->inject('response') ->action(function (string $collection, string $document, array $queries, Adapter $adapter, Response $response) { foreach ($queries as $index => $query) { - $query = json_encode($query); + $query = json_decode($query, true); $queries[$index] = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); } From 6fb801bfa37a9aa7dbe3767b445550d2cba7bc9a Mon Sep 17 00:00:00 2001 From: fogelito Date: Sat, 9 Dec 2023 18:40:36 +0100 Subject: [PATCH 15/32] json_encode queries find method --- app/endpoints.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/endpoints.php b/app/endpoints.php index 7aa016c..d5fd36d 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -253,7 +253,7 @@ ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('document', '', new Text(MAX_STRING_SIZE, 0)) - ->param('queries', [], new ArrayList(new Text(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) + ->param('queries', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) ->inject('adapter') ->inject('response') ->action(function (string $collection, string $document, array $queries, Adapter $adapter, Response $response) { @@ -269,7 +269,7 @@ Http::get('/v1/collections/:collection/documents') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('queries', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) + ->param('queries', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) ->param('limit', 25, new Integer(), '', true) ->param('offset', null, new Integer(), '', true) ->param('orderAttributes', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) @@ -280,8 +280,9 @@ ->inject('adapter') ->inject('response') ->action(function (string $collection, array $queries, ?int $limit, ?int $offset, array $orderAttributes, array $orderTypes, array $cursor, string $cursorDirection, ?int $timeout, Adapter $adapter, Response $response) { - foreach ($queries as &$query) { - $query = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); + foreach ($queries as $index => $query) { + $query = json_decode($query, true); + $queries[$index] = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); } $output = $adapter->find($collection, $queries, $limit, $offset, $orderAttributes, $orderTypes, $cursor, $cursorDirection, $timeout); From 9a28cf20ce9f0769cd27a4018c93a6af044a93ac Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 10 Dec 2023 11:55:28 +0100 Subject: [PATCH 16/32] Count endpoints.php --- app/endpoints.php | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/app/endpoints.php b/app/endpoints.php index d5fd36d..49a57ad 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -12,6 +12,7 @@ use Utopia\Http\Validator\FloatValidator; use Utopia\Http\Validator\Integer; use Utopia\Http\Validator\Text; +use function PHPUnit\Framework\isNull; Http::get('/mock/error') ->groups(['api', 'mock']) @@ -270,16 +271,25 @@ ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('queries', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) - ->param('limit', 25, new Integer(), '', true) - ->param('offset', null, new Integer(), '', true) + ->param('limit', 25, new Integer(true), '', true) + ->param('offset', null, new Integer(true), '', true) ->param('orderAttributes', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) ->param('orderTypes', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) ->param('cursor', [], new Assoc(MAX_STRING_SIZE), '', true) ->param('cursorDirection', Database::CURSOR_AFTER, new Text(MAX_STRING_SIZE, 0), '', true) - ->param('timeout', null, new Integer(), '', true) + ->param('timeout', null, new Integer(true), '', true) ->inject('adapter') ->inject('response') - ->action(function (string $collection, array $queries, ?int $limit, ?int $offset, array $orderAttributes, array $orderTypes, array $cursor, string $cursorDirection, ?int $timeout, Adapter $adapter, Response $response) { + ->action(function (string $collection, array $queries, int|string $limit, int|string|null $offset, array $orderAttributes, array $orderTypes, array $cursor, string $cursorDirection, int|string|null $timeout, Adapter $adapter, Response $response) { + + if(!isNull($limit)){ + $limit = intval($limit); + } + + if(!isNull($timeout)){ + $timeout = intval($timeout); + } + foreach ($queries as $index => $query) { $query = json_decode($query, true); $queries[$index] = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); @@ -310,14 +320,23 @@ Http::get('/v1/collections/:collection/documents-count') ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('queries', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) - ->param('max', null, new Integer(), '', true) - ->param('timeout', null, new Integer(), '', true) + ->param('queries', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) + ->param('max', null, new Integer(true), '', true) + ->param('timeout', null, new Integer(true), '', true) ->inject('adapter') ->inject('response') - ->action(function (string $collection, array $queries, ?int $max, ?int $timeout, Adapter $adapter, Response $response) { - foreach ($queries as &$query) { - $query = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); + ->action(function (string $collection, array $queries, int|string|null $max, int|string|null $timeout, Adapter $adapter, Response $response) { + if(!isNull($timeout)){ + $timeout = intval($timeout); + } + + if(!isNull($max)){ + $max = intval($max); + } + + foreach ($queries as $index => $query) { + $query = json_decode($query, true); + $queries[$index] = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); } $output = $adapter->count($collection, $queries, $max, $timeout); From adcd7d3bb4e145fc4a819fcd9ac6b01ad63e356c Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 10 Dec 2023 13:57:49 +0100 Subject: [PATCH 17/32] Error exceptions --- app/endpoints.php | 21 +++++++++++++++------ app/http.php | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/endpoints.php b/app/endpoints.php index 49a57ad..6fdc606 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -303,14 +303,23 @@ ->groups(['api']) ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) - ->param('queries', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) - ->param('max', null, new Integer(), '', true) - ->param('timeout', null, new Integer(), '', true) + ->param('queries', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) + ->param('max', null, new Integer(true), '', true) + ->param('timeout', null, new Integer(true), '', true) ->inject('adapter') ->inject('response') - ->action(function (string $collection, string $attribute, array $queries, ?int $max, ?int $timeout, Adapter $adapter, Response $response) { - foreach ($queries as &$query) { - $query = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); + ->action(function (string $collection, string $attribute, array $queries, int|string|null $max, int|string|null $timeout, Adapter $adapter, Response $response) { + if(!isNull($timeout)){ + $timeout = intval($timeout); + } + + if(!isNull($max)){ + $max = intval($max); + } + + foreach ($queries as $index => $query) { + $query = json_decode($query, true); + $queries[$index] = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); } $output = $adapter->sum($collection, $attribute, $queries, $max, $timeout); diff --git a/app/http.php b/app/http.php index b2b0c22..99eb489 100644 --- a/app/http.php +++ b/app/http.php @@ -75,7 +75,7 @@ PDO::ATTR_TIMEOUT => 15, // Seconds PDO::ATTR_PERSISTENT => false, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_ERRMODE => Http::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // PDO will throw a PDOException PDO::ATTR_EMULATE_PREPARES => true, PDO::ATTR_STRINGIFY_FETCHES => true )); From df736a6b77159483f50015035b2b96fd7b29e182 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 10 Dec 2023 18:37:54 +0100 Subject: [PATCH 18/32] No reference --- app/endpoints.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/endpoints.php b/app/endpoints.php index 6fdc606..bb58fd6 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -78,12 +78,12 @@ ->inject('adapter') ->inject('response') ->action(function (string $collection, array $attributes, array $indexes, Adapter $adapter, Response $response) { - foreach ($attributes as &$attribute) { - $attribute = new Document($attribute); + foreach ($attributes as $key => $attribute) { + $attributes[$key] = new Document($attribute); } - foreach ($indexes as &$index) { - $index = new Document($index); + foreach ($indexes as $key => $index) { + $indexes[$key] = new Document($index); } $output = $adapter->createCollection($collection, $attributes, $indexes); From 43cc75c3a08502b8895e698dbda19401aa7388d9 Mon Sep 17 00:00:00 2001 From: fogelito Date: Wed, 13 Dec 2023 10:58:22 +0200 Subject: [PATCH 19/32] Build command --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7146af6..2cd59b3 100644 --- a/README.md +++ b/README.md @@ -1 +1,4 @@ -# Utopia PHP Database Proxy \ No newline at end of file +# Utopia PHP Database Proxy + +Build: +docker build -t database-proxy . \ No newline at end of file From 9f76dee0a2d1ed3f367d223e5834d6c782d0e7e0 Mon Sep 17 00:00:00 2001 From: fogelito Date: Wed, 13 Dec 2023 11:52:40 +0200 Subject: [PATCH 20/32] composer.lock --- composer.lock | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/composer.lock b/composer.lock index 21b09da..50f2051 100644 --- a/composer.lock +++ b/composer.lock @@ -810,16 +810,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.17.1", + "version": "v4.18.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", "shasum": "" }, "require": { @@ -860,9 +860,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" }, - "time": "2023-08-13T19:53:39+00:00" + "time": "2023-12-10T21:03:43+00:00" }, { "name": "phar-io/manifest", @@ -977,16 +977,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.48", + "version": "1.10.49", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "087ed4b5f4a7a6e8f3bbdfbfe98ce5c181380bc6" + "reference": "9367ba4c4f6ad53e9efb594d74a8941563caccf6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/087ed4b5f4a7a6e8f3bbdfbfe98ce5c181380bc6", - "reference": "087ed4b5f4a7a6e8f3bbdfbfe98ce5c181380bc6", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9367ba4c4f6ad53e9efb594d74a8941563caccf6", + "reference": "9367ba4c4f6ad53e9efb594d74a8941563caccf6", "shasum": "" }, "require": { @@ -1035,20 +1035,20 @@ "type": "tidelift" } ], - "time": "2023-12-08T14:34:28+00:00" + "time": "2023-12-12T10:05:12+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "10.1.9", + "version": "10.1.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "a56a9ab2f680246adcf3db43f38ddf1765774735" + "reference": "599109c8ca6bae97b23482d557d2874c25a65e59" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/a56a9ab2f680246adcf3db43f38ddf1765774735", - "reference": "a56a9ab2f680246adcf3db43f38ddf1765774735", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/599109c8ca6bae97b23482d557d2874c25a65e59", + "reference": "599109c8ca6bae97b23482d557d2874c25a65e59", "shasum": "" }, "require": { @@ -1105,7 +1105,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.9" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.10" }, "funding": [ { @@ -1113,7 +1113,7 @@ "type": "github" } ], - "time": "2023-11-23T12:23:20+00:00" + "time": "2023-12-11T06:28:43+00:00" }, { "name": "phpunit/php-file-iterator", From 0477586539dd7b73993bdaa82f1f5e75e3962a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 3 Jan 2024 08:26:09 +0000 Subject: [PATCH 21/32] PR review changes --- app/endpoints.php | 18 +++++------ app/http.php | 79 ++++++++++++++++++++++------------------------- composer.lock | 68 ++++++++++++++++++++-------------------- 3 files changed, 80 insertions(+), 85 deletions(-) diff --git a/app/endpoints.php b/app/endpoints.php index bb58fd6..8d7febe 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -12,7 +12,6 @@ use Utopia\Http\Validator\FloatValidator; use Utopia\Http\Validator\Integer; use Utopia\Http\Validator\Text; -use function PHPUnit\Framework\isNull; Http::get('/mock/error') ->groups(['api', 'mock']) @@ -281,13 +280,14 @@ ->inject('adapter') ->inject('response') ->action(function (string $collection, array $queries, int|string $limit, int|string|null $offset, array $orderAttributes, array $orderTypes, array $cursor, string $cursorDirection, int|string|null $timeout, Adapter $adapter, Response $response) { + $limit = intval($limit); - if(!isNull($limit)){ - $limit = intval($limit); + if(!is_null($timeout)) { + $timeout = intval($timeout); } - if(!isNull($timeout)){ - $timeout = intval($timeout); + if(!is_null($offset)) { + $offset = intval($offset); } foreach ($queries as $index => $query) { @@ -309,11 +309,11 @@ ->inject('adapter') ->inject('response') ->action(function (string $collection, string $attribute, array $queries, int|string|null $max, int|string|null $timeout, Adapter $adapter, Response $response) { - if(!isNull($timeout)){ + if(!is_null($timeout)) { $timeout = intval($timeout); } - if(!isNull($max)){ + if(!is_null($max)) { $max = intval($max); } @@ -335,11 +335,11 @@ ->inject('adapter') ->inject('response') ->action(function (string $collection, array $queries, int|string|null $max, int|string|null $timeout, Adapter $adapter, Response $response) { - if(!isNull($timeout)){ + if(!is_null($timeout)) { $timeout = intval($timeout); } - if(!isNull($max)){ + if(!is_null($max)) { $max = intval($max); } diff --git a/app/http.php b/app/http.php index 99eb489..c918396 100644 --- a/app/http.php +++ b/app/http.php @@ -195,47 +195,6 @@ } }); -function logError(Log $log, Throwable $error, string $action, Logger $logger = null, ?Route $route = null): void -{ - Console::error('[Error] Type: ' . get_class($error)); - Console::error('[Error] Message: ' . $error->getMessage()); - Console::error('[Error] File: ' . $error->getFile()); - Console::error('[Error] Line: ' . $error->getLine()); - - if ($logger && ($error->getCode() === 500 || $error->getCode() === 0)) { - $version = (string) Http::getEnv('UTOPIA_DATABASE_PROXY_VERSION', ''); - if (empty($version)) { - $version = 'UNKNOWN'; - } - - $log->setNamespace("database-proxy"); - $log->setServer(\gethostname() !== false ? \gethostname() : null); - $log->setVersion($version); - $log->setType(Log::TYPE_ERROR); - $log->setMessage($error->getMessage()); - - if ($route) { - $log->addTag('method', $route->getMethod()); - $log->addTag('url', $route->getPath()); - } - - $log->addTag('code', \strval($error->getCode())); - $log->addTag('verboseType', get_class($error)); - - $log->addExtra('file', $error->getFile()); - $log->addExtra('line', $error->getLine()); - $log->addExtra('trace', $error->getTraceAsString()); - $log->addExtra('detailedTrace', $error->getTrace()); - - $log->setAction($action); - - $log->setEnvironment(Http::isProduction() ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); - - $responseCode = $logger->addLog($log); - Console::info('Log pushed with status code: ' . $responseCode); - } -} - Http::error() ->inject('route') ->inject('error') @@ -243,7 +202,43 @@ function logError(Log $log, Throwable $error, string $action, Logger $logger = n ->inject('response') ->inject('log') ->action(function (?Route $route, Throwable $error, ?Logger $logger, Response $response, Log $log) { - logError($log, $error, "httpError", $logger, $route); + Console::error('[Error] Type: ' . get_class($error)); + Console::error('[Error] Message: ' . $error->getMessage()); + Console::error('[Error] File: ' . $error->getFile()); + Console::error('[Error] Line: ' . $error->getLine()); + + if ($logger && ($error->getCode() === 500 || $error->getCode() === 0)) { + $version = (string) Http::getEnv('UTOPIA_DATABASE_PROXY_VERSION', ''); + if (empty($version)) { + $version = 'UNKNOWN'; + } + + $log->setNamespace("database-proxy"); + $log->setServer(\gethostname() !== false ? \gethostname() : null); + $log->setVersion($version); + $log->setType(Log::TYPE_ERROR); + $log->setMessage($error->getMessage()); + + if ($route) { + $log->addTag('method', $route->getMethod()); + $log->addTag('url', $route->getPath()); + } + + $log->addTag('code', \strval($error->getCode())); + $log->addTag('verboseType', get_class($error)); + + $log->addExtra('file', $error->getFile()); + $log->addExtra('line', $error->getLine()); + $log->addExtra('trace', $error->getTraceAsString()); + $log->addExtra('detailedTrace', $error->getTrace()); + + $log->setAction('httpError'); + + $log->setEnvironment(Http::isProduction() ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING); + + $responseCode = $logger->addLog($log); + Console::info('Log pushed with status code: ' . $responseCode); + } switch ($error->getCode()) { case 400: // Error allowed publicly diff --git a/composer.lock b/composer.lock index 50f2051..5fefd7e 100644 --- a/composer.lock +++ b/composer.lock @@ -977,16 +977,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.49", + "version": "1.10.50", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "9367ba4c4f6ad53e9efb594d74a8941563caccf6" + "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9367ba4c4f6ad53e9efb594d74a8941563caccf6", - "reference": "9367ba4c4f6ad53e9efb594d74a8941563caccf6", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4", + "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4", "shasum": "" }, "require": { @@ -1035,27 +1035,27 @@ "type": "tidelift" } ], - "time": "2023-12-12T10:05:12+00:00" + "time": "2023-12-13T10:59:42+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "10.1.10", + "version": "10.1.11", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "599109c8ca6bae97b23482d557d2874c25a65e59" + "reference": "78c3b7625965c2513ee96569a4dbb62601784145" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/599109c8ca6bae97b23482d557d2874c25a65e59", - "reference": "599109c8ca6bae97b23482d557d2874c25a65e59", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/78c3b7625965c2513ee96569a4dbb62601784145", + "reference": "78c3b7625965c2513ee96569a4dbb62601784145", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=8.1", "phpunit/php-file-iterator": "^4.0", "phpunit/php-text-template": "^3.0", @@ -1105,7 +1105,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.10" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.11" }, "funding": [ { @@ -1113,7 +1113,7 @@ "type": "github" } ], - "time": "2023-12-11T06:28:43+00:00" + "time": "2023-12-21T15:38:30+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1705,20 +1705,20 @@ }, { "name": "sebastian/complexity", - "version": "3.1.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "68cfb347a44871f01e33ab0ef8215966432f6957" + "reference": "68ff824baeae169ec9f2137158ee529584553799" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68cfb347a44871f01e33ab0ef8215966432f6957", - "reference": "68cfb347a44871f01e33ab0ef8215966432f6957", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", + "reference": "68ff824baeae169ec9f2137158ee529584553799", "shasum": "" }, "require": { - "nikic/php-parser": "^4.10", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=8.1" }, "require-dev": { @@ -1727,7 +1727,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.2-dev" } }, "autoload": { @@ -1751,7 +1751,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/3.1.0" + "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" }, "funding": [ { @@ -1759,20 +1759,20 @@ "type": "github" } ], - "time": "2023-09-28T11:50:59+00:00" + "time": "2023-12-21T08:37:17+00:00" }, { "name": "sebastian/diff", - "version": "5.0.3", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b" + "reference": "fbf413a49e54f6b9b17e12d900ac7f6101591b7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/912dc2fbe3e3c1e7873313cc801b100b6c68c87b", - "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/fbf413a49e54f6b9b17e12d900ac7f6101591b7f", + "reference": "fbf413a49e54f6b9b17e12d900ac7f6101591b7f", "shasum": "" }, "require": { @@ -1785,7 +1785,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -1818,7 +1818,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/diff/tree/5.1.0" }, "funding": [ { @@ -1826,7 +1826,7 @@ "type": "github" } ], - "time": "2023-05-01T07:48:21+00:00" + "time": "2023-12-22T10:55:06+00:00" }, { "name": "sebastian/environment", @@ -2034,20 +2034,20 @@ }, { "name": "sebastian/lines-of-code", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d" + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/649e40d279e243d985aa8fb6e74dd5bb28dc185d", - "reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", "shasum": "" }, "require": { - "nikic/php-parser": "^4.10", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=8.1" }, "require-dev": { @@ -2080,7 +2080,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.1" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" }, "funding": [ { @@ -2088,7 +2088,7 @@ "type": "github" } ], - "time": "2023-08-31T09:25:50+00:00" + "time": "2023-12-21T08:38:20+00:00" }, { "name": "sebastian/object-enumerator", From 975503922bd5c0acad19068e811bcd07fad15def Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 3 Jan 2024 08:53:23 +0000 Subject: [PATCH 22/32] Fix failinig tests --- tests/ProxyTest.php | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php index 49b3893..211113e 100644 --- a/tests/ProxyTest.php +++ b/tests/ProxyTest.php @@ -20,9 +20,15 @@ final class ProxyTest extends TestCase protected bool $defaultAuthStatus = true; protected int $timeout = 10000; // Milliseconds + protected string $testUniqueId; + protected function setUp(): void { - $this->namespace .= '-' . \uniqid(); + $this->testUniqueId = \uniqid(); + $this->namespace .= '-' . $this->testUniqueId; + $this->defaultDatabase .= '-' . $this->testUniqueId; + + $this->call('POST', '/databases', [ 'database' => $this->defaultDatabase ]); } /** @@ -53,40 +59,56 @@ public function testSecret(): void public function testDefaultDatabase(): void { - $response = $this->call('GET', '/databases/wrong-default-database'); + $response = $this->call('GET', '/databases/' . $this->defaultDatabase); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertTrue($body['output']); + + $response = $this->call('GET', '/databases/' . $this->defaultDatabase . '-wrong'); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertFalse($body['output']); + $response = $this->call('POST', '/databases', [ 'database' => $this->defaultDatabase . '-wrong' ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertTrue($body['output']); + + $response = $this->call('GET', '/databases/' . $this->defaultDatabase . '-wrong'); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertTrue($body['output']); + $correctDefaultDatabase = $this->defaultDatabase; - $this->defaultDatabase = 'wrong-default-database'; + $this->defaultDatabase .= '-wrong'; $response = $this->call('POST', '/collections', [ 'collection' => 'default-db-test', 'attributes' => [], 'indexes' => [] ]); + $this->defaultDatabase = $correctDefaultDatabase; self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); - $response = $this->call('GET', '/databases/wrong-default-database'); + $response = $this->call('GET', '/collections/default-db-test?database=' . $this->defaultDatabase . '-wrong'); + self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); - self::assertFalse($body['output']); + self::assertTrue($body['output']); + - $response = $this->call('GET', '/collections/default-db-test?database=wrong-default-database'); + $response = $this->call('GET', '/collections/default-db-test?database=' . $this->defaultDatabase); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertFalse($body['output']); - - $this->defaultDatabase = $correctDefaultDatabase; } public function testNamespace(): void { $correctNamespace = $this->namespace; - $this->namespace = $this->namespace . '-wrong'; + $this->namespace .= '-wrong'; $response = $this->call('GET', '/collections/cars?database=' . $this->defaultDatabase); self::assertEquals(200, $response->getStatusCode()); From a8ae3a3c615d2c2a3c945c04ae72ef60dc720ee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sat, 27 Jan 2024 17:02:35 +0000 Subject: [PATCH 23/32] Changes after HTTP and Auth refactor --- app/endpoints.php | 27 +++------- app/http.php | 65 +++++++++++------------ composer.json | 6 +-- composer.lock | 116 +++++++++++++++++++----------------------- tests/ProxyTest.php | 2 +- tests/benchmark/k6.js | 2 +- 6 files changed, 95 insertions(+), 123 deletions(-) diff --git a/app/endpoints.php b/app/endpoints.php index 8d7febe..40b3368 100644 --- a/app/endpoints.php +++ b/app/endpoints.php @@ -276,16 +276,11 @@ ->param('orderTypes', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) ->param('cursor', [], new Assoc(MAX_STRING_SIZE), '', true) ->param('cursorDirection', Database::CURSOR_AFTER, new Text(MAX_STRING_SIZE, 0), '', true) - ->param('timeout', null, new Integer(true), '', true) ->inject('adapter') ->inject('response') - ->action(function (string $collection, array $queries, int|string $limit, int|string|null $offset, array $orderAttributes, array $orderTypes, array $cursor, string $cursorDirection, int|string|null $timeout, Adapter $adapter, Response $response) { + ->action(function (string $collection, array $queries, int|string $limit, int|string|null $offset, array $orderAttributes, array $orderTypes, array $cursor, string $cursorDirection, Adapter $adapter, Response $response) { $limit = intval($limit); - if(!is_null($timeout)) { - $timeout = intval($timeout); - } - if(!is_null($offset)) { $offset = intval($offset); } @@ -295,7 +290,7 @@ $queries[$index] = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); } - $output = $adapter->find($collection, $queries, $limit, $offset, $orderAttributes, $orderTypes, $cursor, $cursorDirection, $timeout); + $output = $adapter->find($collection, $queries, $limit, $offset, $orderAttributes, $orderTypes, $cursor, $cursorDirection); $response->json(['output' => $output]); }); @@ -305,14 +300,9 @@ ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) ->param('queries', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) ->param('max', null, new Integer(true), '', true) - ->param('timeout', null, new Integer(true), '', true) ->inject('adapter') ->inject('response') - ->action(function (string $collection, string $attribute, array $queries, int|string|null $max, int|string|null $timeout, Adapter $adapter, Response $response) { - if(!is_null($timeout)) { - $timeout = intval($timeout); - } - + ->action(function (string $collection, string $attribute, array $queries, int|string|null $max, Adapter $adapter, Response $response) { if(!is_null($max)) { $max = intval($max); } @@ -322,7 +312,7 @@ $queries[$index] = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); } - $output = $adapter->sum($collection, $attribute, $queries, $max, $timeout); + $output = $adapter->sum($collection, $attribute, $queries, $max); $response->json(['output' => $output]); }); @@ -331,14 +321,9 @@ ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) ->param('queries', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) ->param('max', null, new Integer(true), '', true) - ->param('timeout', null, new Integer(true), '', true) ->inject('adapter') ->inject('response') - ->action(function (string $collection, array $queries, int|string|null $max, int|string|null $timeout, Adapter $adapter, Response $response) { - if(!is_null($timeout)) { - $timeout = intval($timeout); - } - + ->action(function (string $collection, array $queries, int|string|null $max, Adapter $adapter, Response $response) { if(!is_null($max)) { $max = intval($max); } @@ -348,7 +333,7 @@ $queries[$index] = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); } - $output = $adapter->count($collection, $queries, $max, $timeout); + $output = $adapter->count($collection, $queries, $max); $response->json(['output' => $output]); }); diff --git a/app/http.php b/app/http.php index c918396..7ae596e 100644 --- a/app/http.php +++ b/app/http.php @@ -3,7 +3,9 @@ require_once __DIR__ . '/../vendor/autoload.php'; use Utopia\CLI\Console; +use Utopia\Database\Adapter; use Utopia\Database\Adapter\MariaDB; +use Utopia\Database\Database; use Utopia\Database\Validator\Authorization; use Utopia\DSN\DSN; use Utopia\Http\Adapter\Swoole\Server; @@ -21,8 +23,6 @@ use Utopia\Pools\Pool; use Utopia\Registry\Registry; -use function Swoole\Coroutine\run; - const MAX_ARRAY_SIZE = 100000; const MAX_STRING_SIZE = 20 * 1024 * 1024; // 20 MB const PAYLOAD_SIZE = 20 * 1024 * 1024; // 20MB @@ -80,7 +80,7 @@ PDO::ATTR_STRINGIFY_FETCHES => true )); $adapter = new MariaDB($pdo); - $adapter->setDefaultDatabase($dsnDatabase); + $adapter->setDatabase($dsnDatabase); return $adapter; }; @@ -89,16 +89,13 @@ return $pool; }); -$http = new Server("0.0.0.0", Http::getEnv('UTOPIA_DATABASE_PROXY_PORT', '80')); - -$http - ->setConfig([ - 'open_http2_protocol' => true, - 'http_compression' => true, - 'http_compression_level' => 6, - 'package_max_length' => PAYLOAD_SIZE, - 'buffer_output_size' => PAYLOAD_SIZE, - ]); +$http = new Server("0.0.0.0", Http::getEnv('UTOPIA_DATABASE_PROXY_PORT', '80'), [ + 'open_http2_protocol' => true, + 'http_compression' => true, + 'http_compression_level' => 6, + 'package_max_length' => PAYLOAD_SIZE, + 'buffer_output_size' => PAYLOAD_SIZE, +]); Http::onStart() ->action(function () { @@ -109,60 +106,62 @@ Http::setResource('logger', fn (Registry $registry) => $registry->get('logger'), ['registry']); Http::setResource('pool', fn (Registry $registry) => $registry->get('pool'), ['registry']); Http::setResource('log', fn () => new Log()); +Http::setResource('authorization', fn () => new Authorization()); Http::setResource('adapterConnection', function (Pool $pool) { $connection = $pool->pop(); return $connection; }, ['pool']); -Http::setResource('adapter', function (Request $request, Connection $adapterConnection) { +Http::setResource('adapter', function (Request $request, Connection $adapterConnection, Authorization $authorization) { $namespace = $request->getHeader('x-utopia-namespace', ''); $timeout = $request->getHeader('x-utopia-timeout', ''); - $defaultDatabase = $request->getHeader('x-utopia-default-database', ''); + $database = $request->getHeader('x-utopia-database', ''); $roles = $request->getHeader('x-utopia-auth-roles', ''); $status = $request->getHeader('x-utopia-auth-status', ''); $statusDefault = $request->getHeader('x-utopia-auth-status-default', ''); + /** + * @var Adapter $resource + */ $resource = $adapterConnection->getResource(); + $resource->setAuthorization($authorization); $resource->setNamespace($namespace); if (!empty($timeout)) { $resource->setTimeout(\intval($timeout)); } else { - $resource->clearTimeout(); + $resource->clearTimeout(Database::EVENT_ALL); } - if (!empty($defaultDatabase)) { - $resource->setDefaultDatabase($defaultDatabase); + if (!empty($database)) { + $resource->setDatabase($database); } else { - $resource->setDefaultDatabase(''); + $resource->setDatabase(''); } - // TODO: This wont work with coroutines - Authorization::cleanRoles(); - Authorization::setRole('any'); + $authorization->cleanRoles(); + $authorization->addRole('any'); foreach (\explode(',', $roles) as $role) { - Authorization::setRole($role); + $authorization->addRole($role); } - // TODO: This wont work with coroutines if (!empty($statusDefault) && $statusDefault === 'false') { - Authorization::setDefaultStatus(false); + $authorization->setDefaultStatus(false); } else { - Authorization::setDefaultStatus(true); + $authorization->setDefaultStatus(true); } - // TODO: This wont work with coroutines if (!empty($status)) { if ($status === 'false') { - Authorization::disable(); + $authorization->disable(); } else { - Authorization::enable(); + $authorization->enable(); } } return $resource; -}, ['request', 'adapterConnection']); +}, ['request', 'adapterConnection', 'authorization']); Http::init() ->groups(['api']) @@ -279,7 +278,5 @@ $response->json($output); }); -run(function () use ($http) { - $app = new Http($http, 'UTC'); - $app->start(); -}); +$app = new Http($http, 'UTC'); +$app->start(); diff --git a/composer.json b/composer.json index bd2a421..805e372 100644 --- a/composer.json +++ b/composer.json @@ -24,9 +24,9 @@ "ext-curl": "*", "ext-json": "*", "ext-swoole": "*", - "utopia-php/framework": "dev-fix-v2-swoole-coroutines as 0.32.99", - "utopia-php/database": "dev-feat-framework-v2 as 0.44.99", - "utopia-php/cache": "0.8.*", + "utopia-php/framework": "0.34.*", + "utopia-php/database": "dev-feat-framework-v2", + "utopia-php/cache": "0.9.*", "utopia-php/cli": "0.16.*", "utopia-php/registry": "0.6.*", "utopia-php/dsn": "0.1.*", diff --git a/composer.lock b/composer.lock index 5fefd7e..7a234dd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c965011dcaabd16e1412e3630ae0686c", + "content-hash": "ad445a0c21278f56603b165891018278", "packages": [ { "name": "jean85/pretty-package-versions", @@ -219,16 +219,16 @@ }, { "name": "utopia-php/cache", - "version": "0.8.0", + "version": "0.9.0", "source": { "type": "git", "url": "https://github.com/utopia-php/cache.git", - "reference": "212e66100a1f32e674fca5d9bc317cc998303089" + "reference": "4fc7b4789b5f0ce74835c1ecfec4f3afe6f0e34e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/cache/zipball/212e66100a1f32e674fca5d9bc317cc998303089", - "reference": "212e66100a1f32e674fca5d9bc317cc998303089", + "url": "https://api.github.com/repos/utopia-php/cache/zipball/4fc7b4789b5f0ce74835c1ecfec4f3afe6f0e34e", + "reference": "4fc7b4789b5f0ce74835c1ecfec4f3afe6f0e34e", "shasum": "" }, "require": { @@ -239,6 +239,7 @@ }, "require-dev": { "laravel/pint": "1.2.*", + "phpstan/phpstan": "1.9.x-dev", "phpunit/phpunit": "^9.3", "vimeo/psalm": "4.13.1" }, @@ -262,9 +263,9 @@ ], "support": { "issues": "https://github.com/utopia-php/cache/issues", - "source": "https://github.com/utopia-php/cache/tree/0.8.0" + "source": "https://github.com/utopia-php/cache/tree/0.9.0" }, - "time": "2022-10-16T16:48:09+00:00" + "time": "2024-01-07T18:11:23+00:00" }, { "name": "utopia-php/cli", @@ -321,31 +322,31 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "1d4ab3dfafbe7a3adfd167e5e288c19634c223ce" + "reference": "b64caf4f1a464b4a9f25b95b8ee7d4542d23d80c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/1d4ab3dfafbe7a3adfd167e5e288c19634c223ce", - "reference": "1d4ab3dfafbe7a3adfd167e5e288c19634c223ce", + "url": "https://api.github.com/repos/utopia-php/database/zipball/b64caf4f1a464b4a9f25b95b8ee7d4542d23d80c", + "reference": "b64caf4f1a464b4a9f25b95b8ee7d4542d23d80c", "shasum": "" }, "require": { "ext-mbstring": "*", "ext-pdo": "*", "php": ">=8.0", - "utopia-php/cache": "0.8.*", - "utopia-php/framework": "dev-fix-v2-swoole-coroutines as 0.31.0", + "utopia-php/cache": "0.9.*", + "utopia-php/framework": "0.34.*", "utopia-php/mongo": "0.3.*" }, "require-dev": { "fakerphp/faker": "^1.14", - "laravel/pint": "1.4.*", + "laravel/pint": "1.13.*", "pcov/clobber": "^2.0", "phpstan/phpstan": "1.10.*", "phpunit/phpunit": "^9.4", "rregeer/phpunit-coverage-check": "^0.3.1", "swoole/ide-helper": "4.8.0", - "utopia-php/cli": "^0.14.0" + "utopia-php/cli": "0.17.*" }, "type": "library", "autoload": { @@ -369,7 +370,7 @@ "issues": "https://github.com/utopia-php/database/issues", "source": "https://github.com/utopia-php/database/tree/feat-framework-v2" }, - "time": "2023-10-05T09:43:50+00:00" + "time": "2024-01-25T11:30:20+00:00" }, { "name": "utopia-php/dsn", @@ -420,16 +421,16 @@ }, { "name": "utopia-php/framework", - "version": "dev-fix-v2-swoole-coroutines", + "version": "0.34.0", "source": { "type": "git", - "url": "https://github.com/utopia-php/framework.git", - "reference": "7405c1fea69443c9034c2f6494a7cbd2d6e6813f" + "url": "https://github.com/utopia-php/http.git", + "reference": "f1f0df17b2fbe855b210a707320a3c85288a3c00" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/7405c1fea69443c9034c2f6494a7cbd2d6e6813f", - "reference": "7405c1fea69443c9034c2f6494a7cbd2d6e6813f", + "url": "https://api.github.com/repos/utopia-php/http/zipball/f1f0df17b2fbe855b210a707320a3c85288a3c00", + "reference": "f1f0df17b2fbe855b210a707320a3c85288a3c00", "shasum": "" }, "require": { @@ -453,17 +454,18 @@ "license": [ "MIT" ], - "description": "A simple, light and advanced PHP framework", + "description": "A simple, light and advanced PHP HTTP framework", "keywords": [ "framework", + "http", "php", "upf" ], "support": { - "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/fix-v2-swoole-coroutines" + "issues": "https://github.com/utopia-php/http/issues", + "source": "https://github.com/utopia-php/http/tree/0.34.0" }, - "time": "2023-10-17T11:16:05+00:00" + "time": "2024-01-24T10:01:25+00:00" }, { "name": "utopia-php/logger", @@ -685,16 +687,16 @@ "packages-dev": [ { "name": "laravel/pint", - "version": "v1.13.7", + "version": "v1.13.10", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "4157768980dbd977f1c4b4cc94997416d8b30ece" + "reference": "e2b5060885694ca30ac008c05dc9d47f10ed1abf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/4157768980dbd977f1c4b4cc94997416d8b30ece", - "reference": "4157768980dbd977f1c4b4cc94997416d8b30ece", + "url": "https://api.github.com/repos/laravel/pint/zipball/e2b5060885694ca30ac008c05dc9d47f10ed1abf", + "reference": "e2b5060885694ca30ac008c05dc9d47f10ed1abf", "shasum": "" }, "require": { @@ -705,13 +707,13 @@ "php": "^8.1.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.38.0", - "illuminate/view": "^10.30.1", + "friendsofphp/php-cs-fixer": "^3.47.1", + "illuminate/view": "^10.41.0", + "larastan/larastan": "^2.8.1", "laravel-zero/framework": "^10.3.0", - "mockery/mockery": "^1.6.6", - "nunomaduro/larastan": "^2.6.4", + "mockery/mockery": "^1.6.7", "nunomaduro/termwind": "^1.15.1", - "pestphp/pest": "^2.24.2" + "pestphp/pest": "^2.31.0" }, "bin": [ "builds/pint" @@ -747,7 +749,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2023-12-05T19:43:12+00:00" + "time": "2024-01-22T09:04:15+00:00" }, { "name": "myclabs/deep-copy", @@ -810,25 +812,27 @@ }, { "name": "nikic/php-parser", - "version": "v4.18.0", + "version": "v5.0.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" + "reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4a21235f7e56e713259a6f76bf4b5ea08502b9dc", + "reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -836,7 +840,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -860,9 +864,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.0" }, - "time": "2023-12-10T21:03:43+00:00" + "time": "2024-01-07T17:17:35+00:00" }, { "name": "phar-io/manifest", @@ -977,16 +981,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.50", + "version": "1.10.57", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4" + "reference": "1627b1d03446904aaa77593f370c5201d2ecc34e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4", - "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1627b1d03446904aaa77593f370c5201d2ecc34e", + "reference": "1627b1d03446904aaa77593f370c5201d2ecc34e", "shasum": "" }, "require": { @@ -1035,7 +1039,7 @@ "type": "tidelift" } ], - "time": "2023-12-13T10:59:42+00:00" + "time": "2024-01-24T11:51:34+00:00" }, { "name": "phpunit/php-code-coverage", @@ -2496,23 +2500,9 @@ "time": "2023-10-10T11:58:32+00:00" } ], - "aliases": [ - { - "package": "utopia-php/database", - "version": "dev-feat-framework-v2", - "alias": "0.44.99", - "alias_normalized": "0.44.99.0" - }, - { - "package": "utopia-php/framework", - "version": "dev-fix-v2-swoole-coroutines", - "alias": "0.32.99", - "alias_normalized": "0.32.99.0" - } - ], + "aliases": [], "minimum-stability": "stable", "stability-flags": { - "utopia-php/framework": 20, "utopia-php/database": 20 }, "prefer-stable": false, diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php index 211113e..71a83e1 100644 --- a/tests/ProxyTest.php +++ b/tests/ProxyTest.php @@ -39,7 +39,7 @@ private function call(string $method, string $endpoint, mixed $body = [], array return Client::fetch($this->endpoint . $endpoint, [ 'x-utopia-secret' => $this->secret, 'x-utopia-namespace' => $this->namespace, - 'x-utopia-default-database' => $this->defaultDatabase, + 'x-utopia-database' => $this->defaultDatabase, 'x-utopia-auth-roles' => \implode(',', $roles), 'x-utopia-auth-status' => $skipAuth ? 'false' : 'true', 'x-utopia-auth-status-default' => $this->defaultAuthStatus ? 'true' : 'false', diff --git a/tests/benchmark/k6.js b/tests/benchmark/k6.js index eb34849..773b045 100644 --- a/tests/benchmark/k6.js +++ b/tests/benchmark/k6.js @@ -6,7 +6,7 @@ export default function () { headers: { 'x-utopia-secret': 'proxy-secret-key', 'x-utopia-namespace': 'utopia', - 'x-utopia-default-database': 'appwrite' + 'x-utopia-database': 'appwrite' } }); check(res, { 'status was 200': (r) => r.status == 200 }); From c8adf3135a980fc7275c5d60cee2d857e009dcb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 29 Jan 2024 09:37:31 +0000 Subject: [PATCH 24/32] Rename to data API --- .env | 10 +++++----- .github/workflows/release.yml | 2 +- Dockerfile | 4 ++-- app/http.php | 16 ++++++++-------- docker-compose.yml | 10 +++++----- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.env b/.env index a3b8212..a6679f2 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ -UTOPIA_DATABASE_PROXY_ENV=development -UTOPIA_DATABASE_PROXY_SECRET=proxy-secret-key -UTOPIA_DATABASE_PROXY_SECRET_CONNECTION=mariadb://root:password@mariadb:3306/appwrite?pool_size=256 -UTOPIA_DATABASE_PROXY_LOGGING_PROVIDER= -UTOPIA_DATABASE_PROXY_LOGGING_CONFIG= \ No newline at end of file +UTOPIA_DATA_API_ENV=development +UTOPIA_DATA_API_SECRET=proxy-secret-key +UTOPIA_DATA_API_SECRET_CONNECTION=mariadb://root:password@mariadb:3306/appwrite?pool_size=256 +UTOPIA_DATA_API_LOGGING_PROVIDER= +UTOPIA_DATA_API_LOGGING_CONFIG= \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 69cda76..8cc9deb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,7 +34,7 @@ jobs: uses: docker/build-push-action@v4 with: build-args: | - UTOPIA_DATABASE_PROXY_VERSION=${{ env.TAG }} + UTOPIA_DATA_API_VERSION=${{ env.TAG }} platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7 context: . push: true diff --git a/Dockerfile b/Dockerfile index 77dcfbf..340c444 100644 --- a/Dockerfile +++ b/Dockerfile @@ -51,8 +51,8 @@ RUN \ # Proxy FROM php:8.1.25-cli-alpine3.16 as final -ARG UTOPIA_DATABASE_PROXY_VERSION -ENV UTOPIA_DATABASE_PROXY_VERSION=$UTOPIA_DATABASE_PROXY_VERSION +ARG UTOPIA_DATA_API_VERSION +ENV UTOPIA_DATA_API_VERSION=$UTOPIA_DATA_API_VERSION LABEL maintainer="team@appwrite.io" diff --git a/app/http.php b/app/http.php index 7ae596e..37236cd 100644 --- a/app/http.php +++ b/app/http.php @@ -32,13 +32,13 @@ require_once __DIR__ . '/endpoints.php'; -Http::setMode((string) Http::getEnv('UTOPIA_DATABASE_PROXY_ENV', Http::MODE_TYPE_PRODUCTION)); +Http::setMode((string) Http::getEnv('UTOPIA_DATA_API_ENV', Http::MODE_TYPE_PRODUCTION)); $registry = new Registry(); $registry->set('logger', function () { - $providerName = Http::getEnv('UTOPIA_DATABASE_PROXY_LOGGING_PROVIDER', ''); - $providerConfig = Http::getEnv('UTOPIA_DATABASE_PROXY_LOGGING_CONFIG', ''); + $providerName = Http::getEnv('UTOPIA_DATA_API_LOGGING_PROVIDER', ''); + $providerConfig = Http::getEnv('UTOPIA_DATA_API_LOGGING_CONFIG', ''); $logger = null; if (!empty($providerName) && !empty($providerConfig) && Logger::hasProvider($providerName)) { @@ -57,7 +57,7 @@ }); $registry->set('pool', function () { - $dsnString = Http::getEnv('UTOPIA_DATABASE_PROXY_SECRET_CONNECTION', '') ?? ''; + $dsnString = Http::getEnv('UTOPIA_DATA_API_SECRET_CONNECTION', '') ?? ''; $dsn = new DSN($dsnString); $dsnHost = $dsn->getHost(); @@ -89,7 +89,7 @@ return $pool; }); -$http = new Server("0.0.0.0", Http::getEnv('UTOPIA_DATABASE_PROXY_PORT', '80'), [ +$http = new Server("0.0.0.0", Http::getEnv('UTOPIA_DATA_API_PORT', '80'), [ 'open_http2_protocol' => true, 'http_compression' => true, 'http_compression_level' => 6, @@ -167,7 +167,7 @@ ->groups(['api']) ->inject('request') ->action(function (Request $request) { - $secret = Http::getEnv('UTOPIA_DATABASE_PROXY_SECRET', ''); + $secret = Http::getEnv('UTOPIA_DATA_API_SECRET', ''); $header = $request->getHeader('x-utopia-secret', ''); if ($header !== $secret) { @@ -207,7 +207,7 @@ Console::error('[Error] Line: ' . $error->getLine()); if ($logger && ($error->getCode() === 500 || $error->getCode() === 0)) { - $version = (string) Http::getEnv('UTOPIA_DATABASE_PROXY_VERSION', ''); + $version = (string) Http::getEnv('UTOPIA_DATA_API_VERSION', ''); if (empty($version)) { $version = 'UNKNOWN'; } @@ -266,7 +266,7 @@ 'file' => $error->getFile(), 'line' => $error->getLine(), 'trace' => $error->getTrace(), - 'version' => Http::getEnv('UTOPIA_DATABASE_PROXY_VERSION', 'UNKNOWN') + 'version' => Http::getEnv('UTOPIA_DATA_API_VERSION', 'UNKNOWN') ]; $response diff --git a/docker-compose.yml b/docker-compose.yml index ae36d9d..022d22a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,11 +13,11 @@ services: ports: - 8088:80 environment: - - UTOPIA_DATABASE_PROXY_ENV - - UTOPIA_DATABASE_PROXY_SECRET - - UTOPIA_DATABASE_PROXY_SECRET_CONNECTION - - UTOPIA_DATABASE_PROXY_LOGGING_PROVIDER - - UTOPIA_DATABASE_PROXY_LOGGING_CONFIG + - UTOPIA_DATA_API_ENV + - UTOPIA_DATA_API_SECRET + - UTOPIA_DATA_API_SECRET_CONNECTION + - UTOPIA_DATA_API_LOGGING_PROVIDER + - UTOPIA_DATA_API_LOGGING_CONFIG mariadb: image: mariadb:10.7 From b12bc388d0e28e57d45eac2c0357176d48abd11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 29 Jan 2024 09:37:44 +0000 Subject: [PATCH 25/32] Update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2cd59b3..cb4873e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Utopia PHP Database Proxy +# Utopia PHP Data API Build: -docker build -t database-proxy . \ No newline at end of file +docker build -t data-api . \ No newline at end of file From 4ea8dc1f9894d684bb9790786dc7c4eefd7c9b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 22 Feb 2024 13:22:47 +0000 Subject: [PATCH 26/32] Rework to have 1 endpoint only --- app/endpoints.php | 401 ----------------------------------- app/http.php | 69 +++++- composer.lock | 85 ++++---- docker-compose.yml | 11 +- tests/ProxyTest.php | 237 +++++++-------------- tests/benchmark/benchmark.sh | 3 - tests/benchmark/k6.js | 13 -- 7 files changed, 188 insertions(+), 631 deletions(-) delete mode 100644 app/endpoints.php delete mode 100644 tests/benchmark/benchmark.sh delete mode 100644 tests/benchmark/k6.js diff --git a/app/endpoints.php b/app/endpoints.php deleted file mode 100644 index 40b3368..0000000 --- a/app/endpoints.php +++ /dev/null @@ -1,401 +0,0 @@ -groups(['api', 'mock']) - ->action(function () { - throw new Exception('Mock error', 500); - }); - -Http::get('/v1/ping') - ->groups(['api']) - ->inject('adapter') - ->inject('response') - ->action(function (Adapter $adapter, Response $response) { - $output = $adapter->ping(); - $response->json(['output' => $output]); - }); - -Http::get('/v1/databases/:database') - ->groups(['api']) - ->param('database', '', new Text(MAX_STRING_SIZE, 0)) - ->inject('adapter') - ->inject('response') - ->action(function (string $database, Adapter $adapter, Response $response) { - $output = $adapter->exists($database, null); - $response->json(['output' => $output]); - }); - -Http::get('/v1/collections/:collection') - ->groups(['api']) - ->param('database', '', new Text(MAX_STRING_SIZE, 0)) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->inject('adapter') - ->inject('response') - ->action(function (string $database, string $collection, Adapter $adapter, Response $response) { - $output = $adapter->exists($database, $collection); - $response->json(['output' => $output]); - }); - -Http::post('/v1/databases') - ->groups(['api']) - ->param('database', '', new Text(MAX_STRING_SIZE, 0)) - ->inject('adapter') - ->inject('response') - ->action(function (string $database, Adapter $adapter, Response $response) { - $output = $adapter->create($database); - $response->json(['output' => $output]); - }); - -Http::delete('/v1/databases/:database') - ->groups(['api']) - ->param('database', '', new Text(MAX_STRING_SIZE, 0)) - ->inject('adapter') - ->inject('response') - ->action(function (string $database, Adapter $adapter, Response $response) { - $output = $adapter->delete($database); - $response->json(['output' => $output]); - }); - -Http::post('/v1/collections') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('attributes', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) - ->param('indexes', [], new ArrayList(new Assoc(MAX_STRING_SIZE), MAX_ARRAY_SIZE), '', true) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, array $attributes, array $indexes, Adapter $adapter, Response $response) { - foreach ($attributes as $key => $attribute) { - $attributes[$key] = new Document($attribute); - } - - foreach ($indexes as $key => $index) { - $indexes[$key] = new Document($index); - } - - $output = $adapter->createCollection($collection, $attributes, $indexes); - $response->json(['output' => $output]); - }); - -Http::delete('/v1/collections/:collection') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, Adapter $adapter, Response $response) { - $output = $adapter->deleteCollection($collection); - $response->json(['output' => $output]); - }); - -Http::post('/v1/collections/:collection/attributes') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) - ->param('type', '', new Text(MAX_STRING_SIZE, 0)) - ->param('size', '', new Integer()) - ->param('signed', true, new Boolean(), '', true) - ->param('array', false, new Boolean(), '', true) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $attribute, string $type, int $size, bool $signed, bool $array, Adapter $adapter, Response $response) { - $output = $adapter->createAttribute($collection, $attribute, $type, $size, $signed, $array); - $response->json(['output' => $output]); - }); - -Http::put('/v1/collections/:collection/attributes/:attribute') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) - ->param('type', '', new Text(MAX_STRING_SIZE, 0)) - ->param('size', '', new Integer()) - ->param('signed', true, new Boolean(), '', true) - ->param('array', false, new Boolean(), '', true) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $attribute, string $type, int $size, bool $signed, bool $array, Adapter $adapter, Response $response) { - $output = $adapter->updateAttribute($collection, $attribute, $type, $size, $signed, $array); - $response->json(['output' => $output]); - }); - -Http::delete('/v1/collections/:collection/attributes/:attribute') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $attribute, Adapter $adapter, Response $response) { - $output = $adapter->deleteAttribute($collection, $attribute); - $response->json(['output' => $output]); - }); - -Http::patch('/v1/collections/:collection/attributes/:attribute/name') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) - ->param('new', '', new Text(MAX_STRING_SIZE, 0)) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $attribute, string $new, Adapter $adapter, Response $response) { - $output = $adapter->renameAttribute($collection, $attribute, $new); - $response->json(['output' => $output]); - }); - -Http::post('/v1/collections/:collection/indexes') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('index', '', new Text(MAX_STRING_SIZE, 0)) - ->param('type', '', new Text(MAX_STRING_SIZE, 0)) - ->param('attributes', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE)) - ->param('lengths', [], new ArrayList(new Integer(), MAX_ARRAY_SIZE)) - ->param('orders', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE)) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $index, string $type, array $attributes, array $lengths, array $orders, Adapter $adapter, Response $response) { - $output = $adapter->createIndex($collection, $index, $type, $attributes, $lengths, $orders); - $response->json(['output' => $output]); - }); - -Http::patch('/v1/collections/:collection/indexes/:index/name') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('index', '', new Text(MAX_STRING_SIZE, 0)) - ->param('new', '', new Text(MAX_STRING_SIZE, 0)) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $index, string $new, Adapter $adapter, Response $response) { - $output = $adapter->renameIndex($collection, $index, $new); - $response->json(['output' => $output]); - }); - -Http::delete('/v1/collections/:collection/indexes/:index') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('index', '', new Text(MAX_STRING_SIZE, 0)) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $index, Adapter $adapter, Response $response) { - $output = $adapter->deleteIndex($collection, $index); - $response->json(['output' => $output]); - }); - -Http::get('/v1/collections/:collection/size') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, Adapter $adapter, Response $response) { - $output = $adapter->getSizeOfCollection($collection); - $response->json(['output' => $output]); - }); - -Http::get('/v1/collections/:collection/widths/attributes') - ->groups(['api']) - ->param('collection', '', new Assoc(MAX_STRING_SIZE)) - ->inject('adapter') - ->inject('response') - ->action(function (array $collection, Adapter $adapter, Response $response) { - $collection = new Document($collection); - - $output = $adapter->getAttributeWidth($collection); - $response->json(['output' => $output]); - }); - -Http::post('/v1/collections/:collection/documents') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('document', '', new Assoc(MAX_STRING_SIZE)) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, array $document, Adapter $adapter, Response $response) { - $document = new Document($document); - - $output = $adapter->createDocument($collection, $document); - $response->json(['output' => $output]); - }); - -Http::put('/v1/collections/:collection/documents') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('document', '', new Assoc(MAX_STRING_SIZE)) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, array $document, Adapter $adapter, Response $response) { - $document = new Document($document); - - $output = $adapter->updateDocument($collection, $document); - $response->json(['output' => $output]); - }); - -Http::delete('/v1/collections/:collection/documents/:document') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('document', '', new Text(MAX_STRING_SIZE, 0)) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $document, Adapter $adapter, Response $response) { - $output = $adapter->deleteDocument($collection, $document); - $response->json(['output' => $output]); - }); - -Http::get('/v1/collections/:collection/documents/:document') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('document', '', new Text(MAX_STRING_SIZE, 0)) - ->param('queries', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $document, array $queries, Adapter $adapter, Response $response) { - foreach ($queries as $index => $query) { - $query = json_decode($query, true); - $queries[$index] = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); - } - - $output = $adapter->getDocument($collection, $document, $queries); - $response->json(['output' => $output]); - }); - -Http::get('/v1/collections/:collection/documents') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('queries', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) - ->param('limit', 25, new Integer(true), '', true) - ->param('offset', null, new Integer(true), '', true) - ->param('orderAttributes', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) - ->param('orderTypes', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) - ->param('cursor', [], new Assoc(MAX_STRING_SIZE), '', true) - ->param('cursorDirection', Database::CURSOR_AFTER, new Text(MAX_STRING_SIZE, 0), '', true) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, array $queries, int|string $limit, int|string|null $offset, array $orderAttributes, array $orderTypes, array $cursor, string $cursorDirection, Adapter $adapter, Response $response) { - $limit = intval($limit); - - if(!is_null($offset)) { - $offset = intval($offset); - } - - foreach ($queries as $index => $query) { - $query = json_decode($query, true); - $queries[$index] = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); - } - - $output = $adapter->find($collection, $queries, $limit, $offset, $orderAttributes, $orderTypes, $cursor, $cursorDirection); - $response->json(['output' => $output]); - }); - -Http::get('/v1/collections/:collection/documents-sum') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) - ->param('queries', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) - ->param('max', null, new Integer(true), '', true) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $attribute, array $queries, int|string|null $max, Adapter $adapter, Response $response) { - if(!is_null($max)) { - $max = intval($max); - } - - foreach ($queries as $index => $query) { - $query = json_decode($query, true); - $queries[$index] = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); - } - - $output = $adapter->sum($collection, $attribute, $queries, $max); - $response->json(['output' => $output]); - }); - -Http::get('/v1/collections/:collection/documents-count') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('queries', [], new ArrayList(new Text(MAX_STRING_SIZE, 0), MAX_ARRAY_SIZE), '', true) - ->param('max', null, new Integer(true), '', true) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, array $queries, int|string|null $max, Adapter $adapter, Response $response) { - if(!is_null($max)) { - $max = intval($max); - } - - foreach ($queries as $index => $query) { - $query = json_decode($query, true); - $queries[$index] = new Query($query['method'], $query['attribute'] ?? '', $query['values'] ?? []); - } - - $output = $adapter->count($collection, $queries, $max); - $response->json(['output' => $output]); - }); - -Http::patch('/v1/collections/:collection/documents/:document/increase') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('document', '', new Text(MAX_STRING_SIZE, 0)) - ->param('attribute', '', new Text(MAX_STRING_SIZE, 0)) - ->param('value', null, new FloatValidator(), '', true) - ->param('min', null, new FloatValidator(), '', true) - ->param('max', null, new FloatValidator(), '', true) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $document, string $attribute, float $value, ?float $min, ?float $max, Adapter $adapter, Response $response) { - $output = $adapter->increaseDocumentAttribute($collection, $document, $attribute, $value, $min, $max); - $response->json(['output' => $output]); - }); - -Http::post('/v1/collections/:collection/relationships') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('relatedCollection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('type', '', new Text(MAX_STRING_SIZE, 0)) - ->param('twoWay', false, new Boolean(), '', true) - ->param('id', '', new Text(MAX_STRING_SIZE, 0), '', true) - ->param('twoWayKey', '', new Text(MAX_STRING_SIZE, 0), '', true) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $relatedCollection, string $type, bool $twoWay, string $id, string $twoWayKey, Adapter $adapter, Response $response) { - $output = $adapter->createRelationship($collection, $relatedCollection, $type, $twoWay, $id, $twoWayKey); - $response->json(['output' => $output]); - }); - -Http::put('/v1/collections/:collection/relationships/:relatedCollection') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('relatedCollection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('type', '', new Text(MAX_STRING_SIZE, 0)) - ->param('twoWay', false, new Boolean()) - ->param('key', '', new Text(MAX_STRING_SIZE, 0)) - ->param('twoWayKey', '', new Text(MAX_STRING_SIZE, 0)) - ->param('newKey', null, new Text(MAX_STRING_SIZE, 0), '', true) - ->param('newTwoWayKey', null, new Text(MAX_STRING_SIZE, 0), '', true) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $relatedCollection, string $type, bool $twoWay, string $key, string $twoWayKey, string $newKey, string $newTwoWayKey, Adapter $adapter, Response $response) { - $output = $adapter->updateRelationship($collection, $relatedCollection, $type, $twoWay, $key, $twoWayKey, $newKey, $newTwoWayKey); - $response->json(['output' => $output]); - }); - -Http::delete('/v1/collections/:collection/relationships/:relatedCollection') - ->groups(['api']) - ->param('collection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('relatedCollection', '', new Text(MAX_STRING_SIZE, 0)) - ->param('type', '', new Text(MAX_STRING_SIZE, 0)) - ->param('twoWay', false, new Boolean()) - ->param('key', '', new Text(MAX_STRING_SIZE, 0)) - ->param('twoWayKey', '', new Text(MAX_STRING_SIZE, 0)) - ->param('side', '', new Text(MAX_STRING_SIZE, 0)) - ->inject('adapter') - ->inject('response') - ->action(function (string $collection, string $relatedCollection, string $type, bool $twoWay, string $key, string $twoWayKey, string $side, Adapter $adapter, Response $response) { - $output = $adapter->deleteRelationship($collection, $relatedCollection, $type, $twoWay, $key, $twoWayKey, $side); - $response->json(['output' => $output]); - }); diff --git a/app/http.php b/app/http.php index 37236cd..c4af2c6 100644 --- a/app/http.php +++ b/app/http.php @@ -6,6 +6,7 @@ use Utopia\Database\Adapter; use Utopia\Database\Adapter\MariaDB; use Utopia\Database\Database; +use Utopia\Database\Document; use Utopia\Database\Validator\Authorization; use Utopia\DSN\DSN; use Utopia\Http\Adapter\Swoole\Server; @@ -13,6 +14,9 @@ use Utopia\Http\Request; use Utopia\Http\Response; use Utopia\Http\Route; +use Utopia\Http\Validator\ArrayList; +use Utopia\Http\Validator\Text; +use Utopia\Http\Validator\Wildcard; use Utopia\Logger\Adapter\AppSignal; use Utopia\Logger\Adapter\LogOwl; use Utopia\Logger\Adapter\Raygun; @@ -30,8 +34,6 @@ // Unlimited memory limit to handle as many coroutines/requests as possible ini_set('memory_limit', '-1'); -require_once __DIR__ . '/endpoints.php'; - Http::setMode((string) Http::getEnv('UTOPIA_DATA_API_ENV', Http::MODE_TYPE_PRODUCTION)); $registry = new Registry(); @@ -175,6 +177,61 @@ } }); +Http::init() + ->groups(['mock']) + ->action(function () { + if (!Http::isDevelopment()) { + throw new Exception('Mock endpoints are not implemented on production.', 404); + } + }); + +Http::get('/mock/error') + ->groups(['api', 'mock']) + ->action(function () { + throw new Exception('Mock error', 500); + }); + +Http::post('/v1/queries') + ->groups(['api']) + ->param('query', '', new Text(1024, 1), 'Method name to run with query') + ->param('params', [], new ArrayList(new Wildcard(), 1024), 'Parameters to pass into a method call', true) + ->inject('adapter') + ->inject('request') + ->inject('response') + ->action(function (string $query, array $params, Adapter $adapter, Request $request, Response $response) { + + $body = $request->getRawPayload(); + $bodyJson = \json_decode($body, false); + + $processArray = function (mixed $self, mixed $json) { + $keys = []; + + foreach ($json as $param) { + if(\is_object($param)) { + $keys[] = new Document((array) $param); + } elseif(\is_array($param)) { + $keys[] = $self($self, $param); + } else { + $keys[] = $param; + } + } + + return $keys; + }; + + $typedParams = $processArray($processArray, $bodyJson->params); + + /** + * @var callable $method + */ + $method = [$adapter, $query]; + $output = call_user_func_array($method, $typedParams); + + $response->json([ + 'output' => $output + ]); + }); + Http::shutdown() ->inject('utopia') ->inject('context') @@ -186,14 +243,6 @@ } }); -Http::init() - ->groups(['mock']) - ->action(function () { - if (!Http::isDevelopment()) { - throw new Exception('Mock endpoints are not implemented on production.', 404); - } - }); - Http::error() ->inject('route') ->inject('error') diff --git a/composer.lock b/composer.lock index 7a234dd..90ebb8d 100644 --- a/composer.lock +++ b/composer.lock @@ -136,16 +136,16 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.28.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", "shasum": "" }, "require": { @@ -153,9 +153,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -199,7 +196,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" }, "funding": [ { @@ -215,7 +212,7 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "utopia-php/cache", @@ -322,12 +319,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "b64caf4f1a464b4a9f25b95b8ee7d4542d23d80c" + "reference": "6dd6562e876c8af6fac3fc7e7fb188e443162c61" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/b64caf4f1a464b4a9f25b95b8ee7d4542d23d80c", - "reference": "b64caf4f1a464b4a9f25b95b8ee7d4542d23d80c", + "url": "https://api.github.com/repos/utopia-php/database/zipball/6dd6562e876c8af6fac3fc7e7fb188e443162c61", + "reference": "6dd6562e876c8af6fac3fc7e7fb188e443162c61", "shasum": "" }, "require": { @@ -370,7 +367,7 @@ "issues": "https://github.com/utopia-php/database/issues", "source": "https://github.com/utopia-php/database/tree/feat-framework-v2" }, - "time": "2024-01-25T11:30:20+00:00" + "time": "2024-02-22T10:24:52+00:00" }, { "name": "utopia-php/dsn", @@ -421,16 +418,16 @@ }, { "name": "utopia-php/framework", - "version": "0.34.0", + "version": "0.34.2", "source": { "type": "git", "url": "https://github.com/utopia-php/http.git", - "reference": "f1f0df17b2fbe855b210a707320a3c85288a3c00" + "reference": "fd126c02b78cc80678c9638f7b335dfb4a841b78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/http/zipball/f1f0df17b2fbe855b210a707320a3c85288a3c00", - "reference": "f1f0df17b2fbe855b210a707320a3c85288a3c00", + "url": "https://api.github.com/repos/utopia-php/http/zipball/fd126c02b78cc80678c9638f7b335dfb4a841b78", + "reference": "fd126c02b78cc80678c9638f7b335dfb4a841b78", "shasum": "" }, "require": { @@ -463,9 +460,9 @@ ], "support": { "issues": "https://github.com/utopia-php/http/issues", - "source": "https://github.com/utopia-php/http/tree/0.34.0" + "source": "https://github.com/utopia-php/http/tree/0.34.2" }, - "time": "2024-01-24T10:01:25+00:00" + "time": "2024-02-20T11:36:56+00:00" }, { "name": "utopia-php/logger", @@ -687,16 +684,16 @@ "packages-dev": [ { "name": "laravel/pint", - "version": "v1.13.10", + "version": "v1.13.11", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "e2b5060885694ca30ac008c05dc9d47f10ed1abf" + "reference": "60a163c3e7e3346a1dec96d3e6f02e6465452552" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/e2b5060885694ca30ac008c05dc9d47f10ed1abf", - "reference": "e2b5060885694ca30ac008c05dc9d47f10ed1abf", + "url": "https://api.github.com/repos/laravel/pint/zipball/60a163c3e7e3346a1dec96d3e6f02e6465452552", + "reference": "60a163c3e7e3346a1dec96d3e6f02e6465452552", "shasum": "" }, "require": { @@ -707,13 +704,13 @@ "php": "^8.1.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.47.1", - "illuminate/view": "^10.41.0", + "friendsofphp/php-cs-fixer": "^3.49.0", + "illuminate/view": "^10.43.0", "larastan/larastan": "^2.8.1", "laravel-zero/framework": "^10.3.0", "mockery/mockery": "^1.6.7", "nunomaduro/termwind": "^1.15.1", - "pestphp/pest": "^2.31.0" + "pestphp/pest": "^2.33.6" }, "bin": [ "builds/pint" @@ -749,7 +746,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2024-01-22T09:04:15+00:00" + "time": "2024-02-13T17:20:13+00:00" }, { "name": "myclabs/deep-copy", @@ -812,16 +809,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.0.0", + "version": "v5.0.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc" + "reference": "2218c2252c874a4624ab2f613d86ac32d227bc69" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4a21235f7e56e713259a6f76bf4b5ea08502b9dc", - "reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/2218c2252c874a4624ab2f613d86ac32d227bc69", + "reference": "2218c2252c874a4624ab2f613d86ac32d227bc69", "shasum": "" }, "require": { @@ -864,9 +861,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.1" }, - "time": "2024-01-07T17:17:35+00:00" + "time": "2024-02-21T19:24:10+00:00" }, { "name": "phar-io/manifest", @@ -981,16 +978,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.57", + "version": "1.10.59", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "1627b1d03446904aaa77593f370c5201d2ecc34e" + "reference": "e607609388d3a6d418a50a49f7940e8086798281" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1627b1d03446904aaa77593f370c5201d2ecc34e", - "reference": "1627b1d03446904aaa77593f370c5201d2ecc34e", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e607609388d3a6d418a50a49f7940e8086798281", + "reference": "e607609388d3a6d418a50a49f7940e8086798281", "shasum": "" }, "require": { @@ -1039,7 +1036,7 @@ "type": "tidelift" } ], - "time": "2024-01-24T11:51:34+00:00" + "time": "2024-02-20T13:59:13+00:00" }, { "name": "phpunit/php-code-coverage", @@ -2380,16 +2377,16 @@ }, { "name": "swoole/ide-helper", - "version": "5.1.1", + "version": "5.1.2", "source": { "type": "git", "url": "https://github.com/swoole/ide-helper.git", - "reference": "69b374d982e7139fc904cc61757e7fede1d9c3d8" + "reference": "33ec7af9111b76d06a70dd31191cc74793551112" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swoole/ide-helper/zipball/69b374d982e7139fc904cc61757e7fede1d9c3d8", - "reference": "69b374d982e7139fc904cc61757e7fede1d9c3d8", + "url": "https://api.github.com/repos/swoole/ide-helper/zipball/33ec7af9111b76d06a70dd31191cc74793551112", + "reference": "33ec7af9111b76d06a70dd31191cc74793551112", "shasum": "" }, "type": "library", @@ -2406,9 +2403,9 @@ "description": "IDE help files for Swoole.", "support": { "issues": "https://github.com/swoole/ide-helper/issues", - "source": "https://github.com/swoole/ide-helper/tree/5.1.1" + "source": "https://github.com/swoole/ide-helper/tree/5.1.2" }, - "time": "2023-12-08T17:56:23+00:00" + "time": "2024-02-01T22:28:11+00:00" }, { "name": "theseer/tokenizer", diff --git a/docker-compose.yml b/docker-compose.yml index 022d22a..2e561ad 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3.1' services: - tests: + data-api: container_name: tests image: proxy-dev build: @@ -19,6 +19,15 @@ services: - UTOPIA_DATA_API_LOGGING_PROVIDER - UTOPIA_DATA_API_LOGGING_CONFIG + adminer: + image: adminer + container_name: appwrite-adminer + restart: always + ports: + - 9506:8080 + networks: + - database + mariadb: image: mariadb:10.7 container_name: utopia-mariadb diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php index 71a83e1..788e23b 100644 --- a/tests/ProxyTest.php +++ b/tests/ProxyTest.php @@ -16,7 +16,7 @@ final class ProxyTest extends TestCase protected string $endpoint = 'http://tests/v1'; protected string $secret = 'proxy-secret-key'; protected string $namespace = 'my-namespace'; - protected string $defaultDatabase = 'appwrite'; + protected string $database = 'appwrite'; protected bool $defaultAuthStatus = true; protected int $timeout = 10000; // Milliseconds @@ -26,9 +26,9 @@ protected function setUp(): void { $this->testUniqueId = \uniqid(); $this->namespace .= '-' . $this->testUniqueId; - $this->defaultDatabase .= '-' . $this->testUniqueId; + $this->database .= '-' . $this->testUniqueId; - $this->call('POST', '/databases', [ 'database' => $this->defaultDatabase ]); + $this->call('POST', '/queries', [ 'query' => 'create', 'params' => [ $this->database ] ]); } /** @@ -39,7 +39,7 @@ private function call(string $method, string $endpoint, mixed $body = [], array return Client::fetch($this->endpoint . $endpoint, [ 'x-utopia-secret' => $this->secret, 'x-utopia-namespace' => $this->namespace, - 'x-utopia-database' => $this->defaultDatabase, + 'x-utopia-database' => $this->database, 'x-utopia-auth-roles' => \implode(',', $roles), 'x-utopia-auth-status' => $skipAuth ? 'false' : 'true', 'x-utopia-auth-status-default' => $this->defaultAuthStatus ? 'true' : 'false', @@ -52,54 +52,79 @@ public function testSecret(): void { $correctSecret = $this->secret; $this->secret = 'wrong-secret'; - $response = $this->call('GET', '/ping'); + $response = $this->call('POST', '/queries', [ 'query' => 'ping' ]); self::assertEquals(401, $response->getStatusCode()); $this->secret = $correctSecret; } - public function testDefaultDatabase(): void + public function testTimeout(): void + { + $correctTimeout = $this->timeout; + + $this->timeout = 600000; + $response = $this->call('POST', '/queries', [ 'query' => 'ping' ]); + self::assertEquals(200, $response->getStatusCode()); + + $this->timeout = -1; + $response = $this->call('POST', '/queries', [ 'query' => 'ping' ]); + self::assertEquals(500, $response->getStatusCode()); + + $this->timeout = $correctTimeout; + } + + public function testMock(): void + { + $correctEndpoint = $this->endpoint; + $this->endpoint = 'http://tests/mock'; + $response = $this->call('GET', '/error'); + self::assertEquals(500, $response->getStatusCode()); + $this->endpoint = $correctEndpoint; + } + + public function testPing(): void { - $response = $this->call('GET', '/databases/' . $this->defaultDatabase); + $response = $this->call('POST', '/queries', [ 'query' => 'ping' ]); + self::assertEquals(200, $response->getStatusCode()); + $body = \json_decode($response->getBody(), true); + self::assertTrue($body['output']); + } + + public function testDatabase(): void + { + $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database ] ]); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); - $response = $this->call('GET', '/databases/' . $this->defaultDatabase . '-wrong'); + $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database . '-wrong' ] ]); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertFalse($body['output']); - $response = $this->call('POST', '/databases', [ 'database' => $this->defaultDatabase . '-wrong' ]); + $response = $this->call('POST', '/queries', [ 'query' => 'create', 'params' => [ $this->database . '-wrong' ] ]); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); - $response = $this->call('GET', '/databases/' . $this->defaultDatabase . '-wrong'); + $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database . '-wrong' ] ]); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); - $correctDefaultDatabase = $this->defaultDatabase; - $this->defaultDatabase .= '-wrong'; - $response = $this->call('POST', '/collections', [ - 'collection' => 'default-db-test', - 'attributes' => [], - 'indexes' => [] - ]); - $this->defaultDatabase = $correctDefaultDatabase; + $correctDatabase = $this->database; + $this->database .= '-wrong'; + $response = $this->call('POST', '/queries', [ 'query' => 'createCollection', 'params' => [ 'default-db-test' ] ]); + $this->database = $correctDatabase; self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); - $response = $this->call('GET', '/collections/default-db-test?database=' . $this->defaultDatabase . '-wrong'); - + $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database . '-wrong', 'default-db-test' ] ]); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); - - $response = $this->call('GET', '/collections/default-db-test?database=' . $this->defaultDatabase); - + $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database, 'default-db-test' ] ]); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertFalse($body['output']); @@ -110,145 +135,122 @@ public function testNamespace(): void $correctNamespace = $this->namespace; $this->namespace .= '-wrong'; - $response = $this->call('GET', '/collections/cars?database=' . $this->defaultDatabase); + $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database, 'cars' ] ]); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertFalse($body['output']); - $response = $this->call('POST', '/collections', [ - 'collection' => 'cars', - 'attributes' => [], - 'indexes' => [] - ]); + $response = $this->call('POST', '/queries', [ 'query' => 'createCollection', 'params' => [ 'cars' ] ]); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); - $response = $this->call('GET', '/collections/cars?database=' . $this->defaultDatabase); + $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database, 'cars' ] ]); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); $this->namespace = $correctNamespace; - $response = $this->call('GET', '/collections/cars?database=' . $this->defaultDatabase); + $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database, 'cars' ] ]); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertFalse($body['output']); } - public function testTimeout(): void - { - $correctTimeout = $this->timeout; - - $this->timeout = 600000; - $response = $this->call('GET', '/ping'); - self::assertEquals(200, $response->getStatusCode()); - - $this->timeout = -1; - $response = $this->call('GET', '/ping'); - self::assertEquals(500, $response->getStatusCode()); - - $this->timeout = $correctTimeout; - } - public function testAuth(): void { - $response = $this->call('POST', '/collections', [ - 'collection' => 'passwords', - 'attributes' => [ - new Document([ - '$id' => 'password', - 'type' => Database::VAR_STRING, - 'size' => 512, - 'required' => true - ]) - ], - 'indexes' => [] - ]); + $response = $this->call('POST', '/queries', [ 'query' => 'createCollection', 'params' => [ 'passwords', [ + new Document([ + '$id' => 'password', + 'type' => Database::VAR_STRING, + 'size' => 512, + 'required' => true + ]) + ] ] ]); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); - $response = $this->call('GET', '/collections/passwords?database=' . $this->defaultDatabase); + $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database, 'passwords' ] ]); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertTrue($body['output']); $docAny = ID::unique(); - $response = $this->call('POST', '/collections/passwords/documents', [ - 'document' => new Document([ + $response = $this->call('POST', '/queries', [ 'query' => 'createDocument', 'params' => [ + 'passwords', new Document([ '$id' => $docAny, '$permissions' => [ Permission::read(Role::any()) ], 'password' => 'any-password' ]) - ]); + ] ]); self::assertEquals(200, $response->getStatusCode()); $docsGuests = ID::unique(); - $response = $this->call('POST', '/collections/passwords/documents', [ - 'document' => new Document([ + $response = $this->call('POST', '/queries', [ 'query' => 'createDocument', 'params' => [ + 'passwords', new Document([ '$id' => $docsGuests, '$permissions' => [ Permission::read(Role::guests()) ], 'password' => 'guests-password' ]) - ]); + ]]); self::assertEquals(200, $response->getStatusCode()); $docUsers = ID::unique(); - $response = $this->call('POST', '/collections/passwords/documents', [ - 'document' => new Document([ + $response = $this->call('POST', '/queries', [ 'query' => 'createDocument', 'params' => [ + 'passwords', new Document([ '$id' => $docUsers, '$permissions' => [ Permission::read(Role::users()) ], 'password' => 'users-password' ]) - ]); + ]]); self::assertEquals(200, $response->getStatusCode()); $docTeam = ID::unique(); - $response = $this->call('POST', '/collections/passwords/documents', [ - 'document' => new Document([ + $response = $this->call('POST', '/queries', [ 'query' => 'createDocument', 'params' => [ + 'passwords', new Document([ '$id' => $docTeam, '$permissions' => [ Permission::read(Role::team('admin')) ], 'password' => 'team-password' ]) - ]); + ]]); self::assertEquals(200, $response->getStatusCode()); - $response = $this->call('GET', '/collections/passwords/documents', [], [], true); + $response = $this->call('POST', '/queries', [ 'query' => 'find', 'params' => ['passwords'] ], [ ], true); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertCount(4, $body['output']); - $response = $this->call('GET', '/collections/passwords/documents', [], [], false); + $response = $this->call('POST', '/queries', [ 'query' => 'find', 'params' => ['passwords'] ], [], false); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertCount(1, $body['output']); - $response = $this->call('GET', '/collections/passwords/documents', [], [ + $response = $this->call('POST', '/queries', [ 'query' => 'find', 'params' => ['passwords'] ], [ 'users' ], false); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertCount(2, $body['output']); - $response = $this->call('GET', '/collections/passwords/documents', [], [ + $response = $this->call('POST', '/queries', [ 'query' => 'find', 'params' => ['passwords'] ], [ 'guests' ], false); self::assertEquals(200, $response->getStatusCode()); $body = \json_decode($response->getBody(), true); self::assertCount(2, $body['output']); - $response = $this->call('GET', '/collections/passwords/documents', [], [ + $response = $this->call('POST', '/queries', [ 'query' => 'find', 'params' => ['passwords'] ], [ 'users', 'guests', 'team:admin' @@ -258,87 +260,4 @@ public function testAuth(): void $body = \json_decode($response->getBody(), true); self::assertCount(4, $body['output']); } - - public function testMock(): void - { - $correctEndpoint = $this->endpoint; - $this->endpoint = 'http://tests/mock'; - $response = $this->call('GET', '/error'); - self::assertEquals(500, $response->getStatusCode()); - $this->endpoint = $correctEndpoint; - } - - public function testPing(): void - { - $response = $this->call('GET', '/ping'); - self::assertEquals(200, $response->getStatusCode()); - $body = \json_decode($response->getBody(), true); - self::assertTrue($body['output']); - } - - public function testExists(): void - { - $response = $this->call('GET', '/collections/books'); - self::assertEquals(400, $response->getStatusCode()); - - $response = $this->call('GET', '/databases/wrong-database'); - self::assertEquals(200, $response->getStatusCode()); - $body = \json_decode($response->getBody(), true); - self::assertFalse($body['output']); - - - $response = $this->call('GET', '/databases/' . $this->defaultDatabase); - self::assertEquals(200, $response->getStatusCode()); - $body = \json_decode($response->getBody(), true); - self::assertTrue($body['output']); - - $response = $this->call('GET', '/collections/books?database=' . $this->defaultDatabase); - self::assertEquals(200, $response->getStatusCode()); - $body = \json_decode($response->getBody(), true); - self::assertFalse($body['output']); - - $response = $this->call('POST', '/collections', [ - 'collection' => 'books', - 'attributes' => [], - 'indexes' => [] - ]); - self::assertEquals(200, $response->getStatusCode()); - $body = \json_decode($response->getBody(), true); - self::assertTrue($body['output']); - - $response = $this->call('GET', '/collections/books?database=' . $this->defaultDatabase); - self::assertEquals(200, $response->getStatusCode()); - $body = \json_decode($response->getBody(), true); - self::assertTrue($body['output']); - } - - /** - * TODO: We do a lot of E2E testing in utopia/database adapter. - * But eventuelly, lets add tests here for all endpoints: - * - * Http::post('/v1/databases') - * Http::delete('/v1/databases/:database') - * Http::post('/v1/collections') - * Http::delete('/v1/collections/:collection') - * Http::post('/v1/collections/:collection/attributes') - * Http::put('/v1/collections/:collection/attributes/:attribute') - * Http::delete('/v1/collections/:collection/attributes/:attribute') - * Http::patch('/v1/collections/:collection/attributes/:attribute/name') - * Http::post('/v1/collections/:collection/indexes') - * Http::patch('/v1/collections/:collection/indexes/:index/name') - * Http::delete('/v1/collections/:collection/indexes/:index') - * Http::get('/v1/collections/:collection/size') - * Http::get('/v1/collections/:collection/widths/attributes') - * Http::post('/v1/collections/:collection/documents') - * Http::put('/v1/collections/:collection/documents') - * Http::delete('/v1/collections/:collection/documents/:document') - * Http::get('/v1/collections/:collection/documents/:document') - * Http::get('/v1/collections/:collection/documents') - * Http::get('/v1/collections/:collection/documents-sum') - * Http::get('/v1/collections/:collection/documents-count') - * Http::patch('/v1/collections/:collection/documents/:document/increase') - * Http::post('/v1/collections/:collection/relationships') - * Http::put('/v1/collections/:collection/relationships/:relatedCollection') - * Http::delete('/v1/collections/:collection/relationships/:relatedCollection') - */ } diff --git a/tests/benchmark/benchmark.sh b/tests/benchmark/benchmark.sh deleted file mode 100644 index b9bdee9..0000000 --- a/tests/benchmark/benchmark.sh +++ /dev/null @@ -1,3 +0,0 @@ -# Operation: Ping -# Max pool size: 256 -k6 run --vus 256 --duration 15s k6.js diff --git a/tests/benchmark/k6.js b/tests/benchmark/k6.js deleted file mode 100644 index 773b045..0000000 --- a/tests/benchmark/k6.js +++ /dev/null @@ -1,13 +0,0 @@ -import http from 'k6/http'; -import { check, sleep } from 'k6'; - -export default function () { - const res = http.get('http://localhost:8088/v1/ping', { - headers: { - 'x-utopia-secret': 'proxy-secret-key', - 'x-utopia-namespace': 'utopia', - 'x-utopia-database': 'appwrite' - } - }); - check(res, { 'status was 200': (r) => r.status == 200 }); -} \ No newline at end of file From 6aa24921bf12eb7ffbf26f0daeda9f432692699b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 22 Feb 2024 13:32:03 +0000 Subject: [PATCH 27/32] Fix CI/CD tests --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index df49a9b..ff9b7e2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,5 +29,5 @@ jobs: - name: Run Tests run: | - docker run --rm -v $PWD:/app --network database-proxy_database -w /app phpswoole/swoole:4.8.12-php8.1-alpine sh -c \ + docker run --rm -v $PWD:/app --network data-api_database -w /app phpswoole/swoole:4.8.12-php8.1-alpine sh -c \ "composer install --profile --ignore-platform-reqs && composer test" \ No newline at end of file From c42c4ae780053ea88b7f0a4e22b04bd37e2acf0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 22 Feb 2024 18:07:39 +0000 Subject: [PATCH 28/32] Fix document convertion --- app/http.php | 8 ++++++-- docker-compose.yml | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/http.php b/app/http.php index c4af2c6..bcf1853 100644 --- a/app/http.php +++ b/app/http.php @@ -199,7 +199,6 @@ ->inject('request') ->inject('response') ->action(function (string $query, array $params, Adapter $adapter, Request $request, Response $response) { - $body = $request->getRawPayload(); $bodyJson = \json_decode($body, false); @@ -208,7 +207,11 @@ foreach ($json as $param) { if(\is_object($param)) { - $keys[] = new Document((array) $param); + $document = (array) $param; + $document = json_decode(json_encode($document), true); + $document = new Document($document); + + $keys[] = $document; } elseif(\is_array($param)) { $keys[] = $self($self, $param); } else { @@ -250,6 +253,7 @@ ->inject('response') ->inject('log') ->action(function (?Route $route, Throwable $error, ?Logger $logger, Response $response, Log $log) { + Console::error('[Error] Type: ' . get_class($error)); Console::error('[Error] Type: ' . get_class($error)); Console::error('[Error] Message: ' . $error->getMessage()); Console::error('[Error] File: ' . $error->getFile()); diff --git a/docker-compose.yml b/docker-compose.yml index 2e561ad..4ca9e60 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.1' services: data-api: - container_name: tests + container_name: data-api image: proxy-dev build: context: . From b44c0e93b52679589167d4d7deafb70ff719dbb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 22 Feb 2024 18:11:45 +0000 Subject: [PATCH 29/32] Add support for Query --- app/http.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app/http.php b/app/http.php index bcf1853..86687ea 100644 --- a/app/http.php +++ b/app/http.php @@ -7,6 +7,7 @@ use Utopia\Database\Adapter\MariaDB; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\DSN\DSN; use Utopia\Http\Adapter\Swoole\Server; @@ -207,11 +208,15 @@ foreach ($json as $param) { if(\is_object($param)) { - $document = (array) $param; - $document = json_decode(json_encode($document), true); - $document = new Document($document); - - $keys[] = $document; + if (property_exists($param, '$id')) { + $document = (array) $param; + $document = json_decode(json_encode($document), true); + $document = new Document($document); + $keys[] = $document; + } else { + $query = new Query($param->method, $param->attribute, $param->values); + $keys[] = $query; + } } elseif(\is_array($param)) { $keys[] = $self($self, $param); } else { From a36945697dabea466a9379a8db5ea86a209eec08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 23 Feb 2024 17:40:18 +0000 Subject: [PATCH 30/32] WIP: Update to raw queries --- app/http.php | 15 ++++----------- tests/ProxyTest.php | 17 ----------------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/app/http.php b/app/http.php index 86687ea..a0537bf 100644 --- a/app/http.php +++ b/app/http.php @@ -118,7 +118,6 @@ Http::setResource('adapter', function (Request $request, Connection $adapterConnection, Authorization $authorization) { $namespace = $request->getHeader('x-utopia-namespace', ''); - $timeout = $request->getHeader('x-utopia-timeout', ''); $database = $request->getHeader('x-utopia-database', ''); $roles = $request->getHeader('x-utopia-auth-roles', ''); $status = $request->getHeader('x-utopia-auth-status', ''); @@ -131,12 +130,6 @@ $resource->setAuthorization($authorization); $resource->setNamespace($namespace); - if (!empty($timeout)) { - $resource->setTimeout(\intval($timeout)); - } else { - $resource->clearTimeout(Database::EVENT_ALL); - } - if (!empty($database)) { $resource->setDatabase($database); } else { @@ -208,14 +201,14 @@ foreach ($json as $param) { if(\is_object($param)) { - if (property_exists($param, '$id')) { + if (property_exists($param, 'method') && !property_exists($param, '$id')) { + $query = new Query($param->method, $param->attribute, $param->values); + $keys[] = $query; + } else { $document = (array) $param; $document = json_decode(json_encode($document), true); $document = new Document($document); $keys[] = $document; - } else { - $query = new Query($param->method, $param->attribute, $param->values); - $keys[] = $query; } } elseif(\is_array($param)) { $keys[] = $self($self, $param); diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php index 788e23b..bb909e6 100644 --- a/tests/ProxyTest.php +++ b/tests/ProxyTest.php @@ -18,7 +18,6 @@ final class ProxyTest extends TestCase protected string $namespace = 'my-namespace'; protected string $database = 'appwrite'; protected bool $defaultAuthStatus = true; - protected int $timeout = 10000; // Milliseconds protected string $testUniqueId; @@ -43,7 +42,6 @@ private function call(string $method, string $endpoint, mixed $body = [], array 'x-utopia-auth-roles' => \implode(',', $roles), 'x-utopia-auth-status' => $skipAuth ? 'false' : 'true', 'x-utopia-auth-status-default' => $this->defaultAuthStatus ? 'true' : 'false', - 'x-utopia-timeout' => \strval($this->timeout), 'content-type' => 'application/json' ], $method, $body); } @@ -57,21 +55,6 @@ public function testSecret(): void $this->secret = $correctSecret; } - public function testTimeout(): void - { - $correctTimeout = $this->timeout; - - $this->timeout = 600000; - $response = $this->call('POST', '/queries', [ 'query' => 'ping' ]); - self::assertEquals(200, $response->getStatusCode()); - - $this->timeout = -1; - $response = $this->call('POST', '/queries', [ 'query' => 'ping' ]); - self::assertEquals(500, $response->getStatusCode()); - - $this->timeout = $correctTimeout; - } - public function testMock(): void { $correctEndpoint = $this->endpoint; From 44a8f0bdfe745596cce271dd36edd30b09be50ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 27 Feb 2024 14:25:35 +0100 Subject: [PATCH 31/32] Fix timeouts and serialize params --- app/http.php | 47 ++++++++++++--------------------------------- composer.lock | 10 +++++----- tests/ProxyTest.php | 17 ++++++++++++++++ 3 files changed, 34 insertions(+), 40 deletions(-) diff --git a/app/http.php b/app/http.php index a0537bf..93be80c 100644 --- a/app/http.php +++ b/app/http.php @@ -5,9 +5,6 @@ use Utopia\CLI\Console; use Utopia\Database\Adapter; use Utopia\Database\Adapter\MariaDB; -use Utopia\Database\Database; -use Utopia\Database\Document; -use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\DSN\DSN; use Utopia\Http\Adapter\Swoole\Server; @@ -15,9 +12,7 @@ use Utopia\Http\Request; use Utopia\Http\Response; use Utopia\Http\Route; -use Utopia\Http\Validator\ArrayList; use Utopia\Http\Validator\Text; -use Utopia\Http\Validator\Wildcard; use Utopia\Logger\Adapter\AppSignal; use Utopia\Logger\Adapter\LogOwl; use Utopia\Logger\Adapter\Raygun; @@ -118,11 +113,14 @@ Http::setResource('adapter', function (Request $request, Connection $adapterConnection, Authorization $authorization) { $namespace = $request->getHeader('x-utopia-namespace', ''); + $timeoutsString = $request->getHeader('x-utopia-timeouts', '[]'); $database = $request->getHeader('x-utopia-database', ''); $roles = $request->getHeader('x-utopia-auth-roles', ''); $status = $request->getHeader('x-utopia-auth-status', ''); $statusDefault = $request->getHeader('x-utopia-auth-status-default', ''); + $timeouts = \json_decode($timeoutsString, true); + /** * @var Adapter $resource */ @@ -130,6 +128,12 @@ $resource->setAuthorization($authorization); $resource->setNamespace($namespace); + $resource->clearTransformations(); + + foreach ($timeouts as $event => $timeout) { + $resource->setTimeout(\intval($timeout), $event); + } + if (!empty($database)) { $resource->setDatabase($database); } else { @@ -188,39 +192,12 @@ Http::post('/v1/queries') ->groups(['api']) ->param('query', '', new Text(1024, 1), 'Method name to run with query') - ->param('params', [], new ArrayList(new Wildcard(), 1024), 'Parameters to pass into a method call', true) + ->param('params', '', new Text(0, 0), 'Base64 of serialized parameters to pass into a method call', true) ->inject('adapter') ->inject('request') ->inject('response') - ->action(function (string $query, array $params, Adapter $adapter, Request $request, Response $response) { - $body = $request->getRawPayload(); - $bodyJson = \json_decode($body, false); - - $processArray = function (mixed $self, mixed $json) { - $keys = []; - - foreach ($json as $param) { - if(\is_object($param)) { - if (property_exists($param, 'method') && !property_exists($param, '$id')) { - $query = new Query($param->method, $param->attribute, $param->values); - $keys[] = $query; - } else { - $document = (array) $param; - $document = json_decode(json_encode($document), true); - $document = new Document($document); - $keys[] = $document; - } - } elseif(\is_array($param)) { - $keys[] = $self($self, $param); - } else { - $keys[] = $param; - } - } - - return $keys; - }; - - $typedParams = $processArray($processArray, $bodyJson->params); + ->action(function (string $query, string $params, Adapter $adapter, Request $request, Response $response) { + $typedParams = \unserialize(\base64_decode($params)); /** * @var callable $method diff --git a/composer.lock b/composer.lock index 90ebb8d..e32cc8f 100644 --- a/composer.lock +++ b/composer.lock @@ -319,12 +319,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "6dd6562e876c8af6fac3fc7e7fb188e443162c61" + "reference": "79fd5790227e039832372f2c6c9c284f6f1284bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/6dd6562e876c8af6fac3fc7e7fb188e443162c61", - "reference": "6dd6562e876c8af6fac3fc7e7fb188e443162c61", + "url": "https://api.github.com/repos/utopia-php/database/zipball/79fd5790227e039832372f2c6c9c284f6f1284bb", + "reference": "79fd5790227e039832372f2c6c9c284f6f1284bb", "shasum": "" }, "require": { @@ -367,7 +367,7 @@ "issues": "https://github.com/utopia-php/database/issues", "source": "https://github.com/utopia-php/database/tree/feat-framework-v2" }, - "time": "2024-02-22T10:24:52+00:00" + "time": "2024-02-27T10:05:08+00:00" }, { "name": "utopia-php/dsn", @@ -2514,5 +2514,5 @@ "platform-overrides": { "php": "8.1" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php index bb909e6..788e23b 100644 --- a/tests/ProxyTest.php +++ b/tests/ProxyTest.php @@ -18,6 +18,7 @@ final class ProxyTest extends TestCase protected string $namespace = 'my-namespace'; protected string $database = 'appwrite'; protected bool $defaultAuthStatus = true; + protected int $timeout = 10000; // Milliseconds protected string $testUniqueId; @@ -42,6 +43,7 @@ private function call(string $method, string $endpoint, mixed $body = [], array 'x-utopia-auth-roles' => \implode(',', $roles), 'x-utopia-auth-status' => $skipAuth ? 'false' : 'true', 'x-utopia-auth-status-default' => $this->defaultAuthStatus ? 'true' : 'false', + 'x-utopia-timeout' => \strval($this->timeout), 'content-type' => 'application/json' ], $method, $body); } @@ -55,6 +57,21 @@ public function testSecret(): void $this->secret = $correctSecret; } + public function testTimeout(): void + { + $correctTimeout = $this->timeout; + + $this->timeout = 600000; + $response = $this->call('POST', '/queries', [ 'query' => 'ping' ]); + self::assertEquals(200, $response->getStatusCode()); + + $this->timeout = -1; + $response = $this->call('POST', '/queries', [ 'query' => 'ping' ]); + self::assertEquals(500, $response->getStatusCode()); + + $this->timeout = $correctTimeout; + } + public function testMock(): void { $correctEndpoint = $this->endpoint; From 8b194dcbeabbd0f7a3f7a177c60167aa9ad99127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 27 Feb 2024 15:42:28 +0100 Subject: [PATCH 32/32] Fix code quality --- app/http.php | 21 ++++++++++++++++++++- tests/ProxyTest.php | 18 +++++++++++++++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/app/http.php b/app/http.php index 93be80c..10e7468 100644 --- a/app/http.php +++ b/app/http.php @@ -118,6 +118,8 @@ $roles = $request->getHeader('x-utopia-auth-roles', ''); $status = $request->getHeader('x-utopia-auth-status', ''); $statusDefault = $request->getHeader('x-utopia-auth-status-default', ''); + $shareTables = $request->getHeader('x-utopia-share-tables', ''); + $tenant = $request->getHeader('x-utopia-tenant', ''); $timeouts = \json_decode($timeoutsString, true); @@ -140,6 +142,18 @@ $resource->setDatabase(''); } + if (!empty($shareTables)) { + if ($shareTables === 'false') { + $resource->setShareTables(false); + } else { + $resource->setShareTables(true); + } + } + + if (!empty($tenant)) { + $resource->setTenant(\intval($tenant)); + } + $authorization->cleanRoles(); $authorization->addRole('any'); foreach (\explode(',', $roles) as $role) { @@ -197,7 +211,12 @@ ->inject('request') ->inject('response') ->action(function (string $query, string $params, Adapter $adapter, Request $request, Response $response) { - $typedParams = \unserialize(\base64_decode($params)); + + if(empty($params)) { + $typedParams = []; + } else { + $typedParams = \unserialize(\base64_decode($params)); + } /** * @var callable $method diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php index 788e23b..95bbde1 100644 --- a/tests/ProxyTest.php +++ b/tests/ProxyTest.php @@ -13,7 +13,7 @@ final class ProxyTest extends TestCase { - protected string $endpoint = 'http://tests/v1'; + protected string $endpoint = 'http://data-api/v1'; protected string $secret = 'proxy-secret-key'; protected string $namespace = 'my-namespace'; protected string $database = 'appwrite'; @@ -36,6 +36,15 @@ protected function setUp(): void */ private function call(string $method, string $endpoint, mixed $body = [], array $roles = [], bool $skipAuth = false): Response { + if(isset($body['params'])) { + $body['params'] = \base64_encode(\serialize($body['params'])); + } + + $timeouts = \json_encode(['*' => $this->timeout]); + if($timeouts == false) { + $timeouts = ''; + } + return Client::fetch($this->endpoint . $endpoint, [ 'x-utopia-secret' => $this->secret, 'x-utopia-namespace' => $this->namespace, @@ -43,7 +52,7 @@ private function call(string $method, string $endpoint, mixed $body = [], array 'x-utopia-auth-roles' => \implode(',', $roles), 'x-utopia-auth-status' => $skipAuth ? 'false' : 'true', 'x-utopia-auth-status-default' => $this->defaultAuthStatus ? 'true' : 'false', - 'x-utopia-timeout' => \strval($this->timeout), + 'x-utopia-timeouts' => $timeouts, 'content-type' => 'application/json' ], $method, $body); } @@ -75,7 +84,7 @@ public function testTimeout(): void public function testMock(): void { $correctEndpoint = $this->endpoint; - $this->endpoint = 'http://tests/mock'; + $this->endpoint = 'http://data-api/mock'; $response = $this->call('GET', '/error'); self::assertEquals(500, $response->getStatusCode()); $this->endpoint = $correctEndpoint; @@ -260,4 +269,7 @@ public function testAuth(): void $body = \json_decode($response->getBody(), true); self::assertCount(4, $body['output']); } + + // TODO: Tests for x-utopia-share-tables + // TODO: Tests for x-utopia-tenant }