diff --git a/.do/deploy.template.yaml b/.do/deploy.template.yaml new file mode 100644 index 0000000..f88e2fd --- /dev/null +++ b/.do/deploy.template.yaml @@ -0,0 +1,62 @@ +spec: + alerts: + - rule: DEPLOYMENT_FAILED + - rule: DOMAIN_FAILED + name: safe-nft-metadata-provider + region: fra + services: + - environment_slug: php + envs: + - key: APP_ENV + scope: RUN_AND_BUILD_TIME + value: prod + - key: COLLECTION_MAX_SUPPLY + scope: RUN_TIME + value: "10000" + - key: COLLECTION_ASSETS_EXTENSION + scope: RUN_TIME + value: png + - key: COLLECTION_HIDDEN_ASSET_EXTENSION + scope: RUN_TIME + value: gif + - key: CACHE_EXPIRATION + scope: RUN_TIME + value: "600" + - key: S3_FS_DRIVER_REGION + scope: RUN_TIME + value: fra1 + - key: S3_FS_DRIVER_ENDPOINT_URL + scope: RUN_TIME + value: https://fra1.digitaloceanspaces.com + - key: S3_FS_DRIVER_ACCESS_KEY + scope: RUN_TIME + type: SECRET + value: YOUR_ACCESS_KEY + - key: S3_FS_DRIVER_SECRET_KEY + scope: RUN_TIME + type: SECRET + value: YOUR_SECRET_KEY + - key: S3_FS_DRIVER_BUCKET_NAME + scope: RUN_TIME + value: my-bucket + - key: S3_FS_DRIVER_OBJECTS_KEY_PREFIX + scope: RUN_TIME + - key: WEB3_SMART_CONTRACT_ADDRESS + scope: RUN_TIME + value: 0xaDC28cac9c1d53cC7457b11CC9423903dc09DDDc + - key: WEB3_HTTP_ENDPOINT + scope: RUN_TIME + type: SECRET + value: https://mainnet.infura.io/v3/YOUR_PROJECT_ID_HERE + github: + branch: main + deploy_on_push: false + repo: liarco-network/safe-nft-metadata-provider + http_port: 8080 + instance_count: 1 + instance_size_slug: basic-xxs + name: metadata-provider + routes: + - path: / + run_command: heroku-php-apache2 public/ + source_dir: / diff --git a/.env b/.env index 03dae85..fe8422b 100644 --- a/.env +++ b/.env @@ -13,16 +13,32 @@ # Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). # https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration +# General collection settings +COLLECTION_MAX_SUPPLY=300 +COLLECTION_ASSETS_EXTENSION=png +COLLECTION_HIDDEN_ASSET_EXTENSION=gif + # Used for TotalSupplyProviers and HTTP headers (default: 10 minutes) CACHE_EXPIRATION=600 +# Local filesystem settings (LocalFilesystemDriver) +LOCAL_FS_DRIVER_COLLECTION_PATH=%kernel.project_dir%/collection + +# AWS S3 filesystem settings (S3FilesystemDriver) +S3_FS_DRIVER_REGION=fra1 +S3_FS_DRIVER_ENDPOINT_URL=https://fra1.digitaloceanspaces.com +S3_FS_DRIVER_ACCESS_KEY=YOUR_ACCESS_KEY +S3_FS_DRIVER_SECRET_KEY=YOUR_SECRET_KEY +S3_FS_DRIVER_BUCKET_NAME=my-bucket +S3_FS_DRIVER_OBJECTS_KEY_PREFIX= + # Used by the EnvVarProvider ENV_TOTAL_SUPPLY=8 # Used by the OpenSeaStatsProvider OPEN_SEA_COLLECTION_SLUG=sketchy-ape-book-club -# Used by the InfuraProvider +# Used by the Web3Provider WEB3_SMART_CONTRACT_ADDRESS=0xaDC28cac9c1d53cC7457b11CC9423903dc09DDDc WEB3_HTTP_ENDPOINT=https://mainnet.infura.io/v3/YOUR_PROJECT_ID_HERE diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..6458f10 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: heroku-php-apache2 public/ diff --git a/README.md b/README.md index e091e5e..9952c00 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,6 @@ Hi! This project implements a basic HTTP metadata (and assets) provider using [Symfony](https://www.symfony.com). -## Dependencies -This project uses PHP `8.1`, but unfortunately the `sc0vu/web3.php` package doesn't support it yet (officially), so you -have to skip the PHP platform requirement when running composer commands until it gets updated. -```bash -composer install --ignore-platform-req=php -``` - ## YouTube tutorial Coming soon... @@ -16,4 +9,7 @@ Coming soon... I suggest deploying this app using [DigitalOcean](https://m.do.co/c/bcc172152095), behind a strong CDN network like [CloudFlare](https://www.cloudflare.com). -By using my link you will be given a 100$ credit on DigitalOcean: https://m.do.co/c/bcc172152095 \ No newline at end of file +By using my link you will be given a 100$ credit on DigitalOcean: https://m.do.co/c/bcc172152095 + +You can also do a one-click deployment on DigitalOcean: +[![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/liarco-network/safe-nft-metadata-provider/tree/main) \ No newline at end of file diff --git a/composer.json b/composer.json index 7dc9f58..50d497a 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,9 @@ "php": ">=8.1", "ext-ctype": "*", "ext-iconv": "*", + "aws/aws-sdk-php": "^3.209", "composer/package-versions-deprecated": "1.11.99.4", + "digitaldonkey/ethereum-php": "dev-master", "doctrine/annotations": "^1.0", "doctrine/doctrine-bundle": "^2.5", "doctrine/doctrine-migrations-bundle": "^3.2", @@ -21,7 +23,6 @@ "nette/utils": "^3.2", "phpdocumentor/reflection-docblock": "^5.3", "phpstan/phpdoc-parser": "^1.2", - "sc0vu/web3.php": "dev-master", "sensio/framework-extra-bundle": "^6.1", "symfony/apache-pack": "^1.0", "symfony/asset": "5.4.*", diff --git a/composer.lock b/composer.lock index d2c2a03..f42656e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,149 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3c017da9ddabdb3447e968396c89f926", + "content-hash": "89c13ee915cd431ab99459e86b6ddec9", "packages": [ + { + "name": "aws/aws-crt-php", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/awslabs/aws-crt-php.git", + "reference": "3942776a8c99209908ee0b287746263725685732" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/3942776a8c99209908ee0b287746263725685732", + "reference": "3942776a8c99209908ee0b287746263725685732", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|^5.4.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "AWS SDK Common Runtime Team", + "email": "aws-sdk-common-runtime@amazon.com" + } + ], + "description": "AWS Common Runtime for PHP", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "crt", + "sdk" + ], + "support": { + "issues": "https://github.com/awslabs/aws-crt-php/issues", + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.0.2" + }, + "time": "2021-09-03T22:57:30+00:00" + }, + { + "name": "aws/aws-sdk-php", + "version": "3.209.3", + "source": { + "type": "git", + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "1c351046d8fd46961f4d020d38624d46065134cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/1c351046d8fd46961f4d020d38624d46065134cf", + "reference": "1c351046d8fd46961f4d020d38624d46065134cf", + "shasum": "" + }, + "require": { + "aws/aws-crt-php": "^1.0.2", + "ext-json": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0", + "guzzlehttp/promises": "^1.4.0", + "guzzlehttp/psr7": "^1.7.0|^2.0", + "mtdowling/jmespath.php": "^2.6", + "php": ">=5.5" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "nette/neon": "^2.3", + "paragonie/random_compat": ">= 2", + "phpunit/phpunit": "^4.8.35|^5.4.3", + "psr/cache": "^1.0", + "psr/simple-cache": "^1.0", + "sebastian/comparator": "^1.2.3" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Aws\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "support": { + "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", + "issues": "https://github.com/aws/aws-sdk-php/issues", + "source": "https://github.com/aws/aws-sdk-php/tree/3.209.3" + }, + "time": "2022-01-11T19:13:42+00:00" + }, { "name": "composer/package-versions-deprecated", "version": "1.11.99.4", @@ -79,6 +220,101 @@ ], "time": "2021-09-13T08:41:34+00:00" }, + { + "name": "digitaldonkey/ecverify", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/digitaldonkey/ecverify.git", + "reference": "fe873f7c1d9662bac9fb6d379d1212954b35dcce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/digitaldonkey/ecverify/zipball/fe873f7c1d9662bac9fb6d379d1212954b35dcce", + "reference": "fe873f7c1d9662bac9fb6d379d1212954b35dcce", + "shasum": "" + }, + "require": { + "kornrunner/keccak": "^1.0", + "php": ">=7", + "simplito/elliptic-php": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ethereum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Thorsten Krug", + "email": "thorsten.krug@consensys.net" + } + ], + "description": "A library integrating Ethereum with typed PHP.", + "support": { + "issues": "https://github.com/digitaldonkey/ecverify/issues", + "source": "https://github.com/digitaldonkey/ecverify/tree/master" + }, + "time": "2018-05-18T17:55:12+00:00" + }, + { + "name": "digitaldonkey/ethereum-php", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/digitaldonkey/ethereum-php.git", + "reference": "8d10bba362e84507c8dff9757a80ee1f35fcaee5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/digitaldonkey/ethereum-php/zipball/8d10bba362e84507c8dff9757a80ee1f35fcaee5", + "reference": "8d10bba362e84507c8dff9757a80ee1f35fcaee5", + "shasum": "" + }, + "require": { + "digitaldonkey/ecverify": "1.0", + "ext-json": "*", + "graze/guzzle-jsonrpc": "~3.0", + "kornrunner/keccak": "^1.0", + "pear/math_biginteger": "^1.0", + "php": ">=7.1" + }, + "require-dev": { + "gossi/php-code-generator": "^0.5.0", + "phpunit/phpunit": "^4.0 || ^5.0" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "Ethereum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Thorsten Krug", + "email": "thorsten.krug@consensys.net" + } + ], + "description": "A library integrating Ethereum with typed PHP.", + "support": { + "issues": "https://github.com/digitaldonkey/ethereum-php/issues", + "source": "https://github.com/digitaldonkey/ethereum-php/tree/master" + }, + "time": "2021-11-16T12:22:35+00:00" + }, { "name": "doctrine/annotations", "version": "1.13.2", @@ -411,16 +647,16 @@ }, { "name": "doctrine/dbal", - "version": "3.2.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "5d54f63541d7bed1156cb5c9b79274ced61890e4" + "reference": "4caf37acf14b513a91dd4f087f7eda424fa25542" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/5d54f63541d7bed1156cb5c9b79274ced61890e4", - "reference": "5d54f63541d7bed1156cb5c9b79274ced61890e4", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/4caf37acf14b513a91dd4f087f7eda424fa25542", + "reference": "4caf37acf14b513a91dd4f087f7eda424fa25542", "shasum": "" }, "require": { @@ -435,14 +671,14 @@ "require-dev": { "doctrine/coding-standard": "9.0.0", "jetbrains/phpstorm-stubs": "2021.1", - "phpstan/phpstan": "1.2.0", + "phpstan/phpstan": "1.3.0", "phpstan/phpstan-strict-rules": "^1.1", - "phpunit/phpunit": "9.5.10", + "phpunit/phpunit": "9.5.11", "psalm/plugin-phpunit": "0.16.1", - "squizlabs/php_codesniffer": "3.6.1", + "squizlabs/php_codesniffer": "3.6.2", "symfony/cache": "^5.2|^6.0", "symfony/console": "^2.0.5|^3.0|^4.0|^5.0|^6.0", - "vimeo/psalm": "4.13.0" + "vimeo/psalm": "4.16.1" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -502,7 +738,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.2.0" + "source": "https://github.com/doctrine/dbal/tree/3.2.1" }, "funding": [ { @@ -518,7 +754,7 @@ "type": "tidelift" } ], - "time": "2021-11-26T21:00:12+00:00" + "time": "2022-01-05T08:52:06+00:00" }, { "name": "doctrine/deprecations", @@ -565,16 +801,16 @@ }, { "name": "doctrine/doctrine-bundle", - "version": "2.5.4", + "version": "2.5.5", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "f6191c50600bad1c0195638413f53aee6158b909" + "reference": "5c086cbbe5327937dd6f90da075f7d421b0f28bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/f6191c50600bad1c0195638413f53aee6158b909", - "reference": "f6191c50600bad1c0195638413f53aee6158b909", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/5c086cbbe5327937dd6f90da075f7d421b0f28bc", + "reference": "5c086cbbe5327937dd6f90da075f7d421b0f28bc", "shasum": "" }, "require": { @@ -587,7 +823,7 @@ "symfony/cache": "^4.3.3|^5.0|^6.0", "symfony/config": "^4.4.3|^5.0|^6.0", "symfony/console": "^3.4.30|^4.3.3|^5.0|^6.0", - "symfony/dependency-injection": "^4.3.3|^5.0|^6.0", + "symfony/dependency-injection": "^4.4.18|^5.0|^6.0", "symfony/deprecation-contracts": "^2.1|^3", "symfony/doctrine-bridge": "^4.4.22|^5.2.7|^6.0", "symfony/framework-bundle": "^3.4.30|^4.3.3|^5.0|^6.0", @@ -658,7 +894,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.5.4" + "source": "https://github.com/doctrine/DoctrineBundle/tree/2.5.5" }, "funding": [ { @@ -674,7 +910,7 @@ "type": "tidelift" } ], - "time": "2021-12-30T18:43:28+00:00" + "time": "2022-01-06T08:56:31+00:00" }, { "name": "doctrine/doctrine-migrations-bundle", @@ -1017,32 +1253,28 @@ }, { "name": "doctrine/lexer", - "version": "1.2.1", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "e864bbf5904cb8f5bb334f99209b48018522f042" + "reference": "9c50f840f257bbb941e6f4a0e94ccf5db5c3f76c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042", - "reference": "e864bbf5904cb8f5bb334f99209b48018522f042", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/9c50f840f257bbb941e6f4a0e94ccf5db5c3f76c", + "reference": "9c50f840f257bbb941e6f4a0e94ccf5db5c3f76c", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpstan/phpstan": "^0.11.8", - "phpunit/phpunit": "^8.2" + "doctrine/coding-standard": "^9.0", + "phpstan/phpstan": "1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.11" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" @@ -1077,7 +1309,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/1.2.1" + "source": "https://github.com/doctrine/lexer/tree/1.2.2" }, "funding": [ { @@ -1093,7 +1325,7 @@ "type": "tidelift" } ], - "time": "2020-05-25T17:44:05+00:00" + "time": "2022-01-12T08:27:12+00:00" }, { "name": "doctrine/migrations", @@ -1302,38 +1534,39 @@ }, { "name": "doctrine/persistence", - "version": "2.2.3", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "5e7bdbbfe9811c06e1f745d1c166647d5c47d6ee" + "reference": "f8af155c1e7963f3d2b4415097d55757bbaa53d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/5e7bdbbfe9811c06e1f745d1c166647d5c47d6ee", - "reference": "5e7bdbbfe9811c06e1f745d1c166647d5c47d6ee", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/f8af155c1e7963f3d2b4415097d55757bbaa53d8", + "reference": "f8af155c1e7963f3d2b4415097d55757bbaa53d8", "shasum": "" }, "require": { - "doctrine/annotations": "^1.0", "doctrine/cache": "^1.11 || ^2.0", "doctrine/collections": "^1.0", "doctrine/deprecations": "^0.5.3", "doctrine/event-manager": "^1.0", "php": "^7.1 || ^8.0", - "psr/cache": "^1.0|^2.0|^3.0" + "psr/cache": "^1.0 || ^2.0 || ^3.0" }, "conflict": { + "doctrine/annotations": "<1.0 || >=2.0", "doctrine/common": "<2.10@dev" }, "require-dev": { "composer/package-versions-deprecated": "^1.11", + "doctrine/annotations": "^1.0", "doctrine/coding-standard": "^6.0 || ^9.0", "doctrine/common": "^3.0", - "phpstan/phpstan": "0.12.84", + "phpstan/phpstan": "1.2.0", "phpunit/phpunit": "^7.5.20 || ^8.0 || ^9.0", - "symfony/cache": "^4.4|^5.0", - "vimeo/psalm": "4.7.0" + "symfony/cache": "^4.4 || ^5.0 || ^6.0", + "vimeo/psalm": "4.13.1" }, "type": "library", "autoload": { @@ -1383,9 +1616,9 @@ ], "support": { "issues": "https://github.com/doctrine/persistence/issues", - "source": "https://github.com/doctrine/persistence/tree/2.2.3" + "source": "https://github.com/doctrine/persistence/tree/2.3.0" }, - "time": "2021-10-25T19:59:10+00:00" + "time": "2022-01-09T19:58:46+00:00" }, { "name": "doctrine/sql-formatter", @@ -1589,6 +1822,69 @@ ], "time": "2021-05-22T16:11:15+00:00" }, + { + "name": "graze/guzzle-jsonrpc", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/graze/guzzle-jsonrpc.git", + "reference": "c4513b7659534792b906723158a8388f54275a61" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/graze/guzzle-jsonrpc/zipball/c4513b7659534792b906723158a8388f54275a61", + "reference": "c4513b7659534792b906723158a8388f54275a61", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0", + "guzzlehttp/promises": "^1.0", + "php": ">=5.5", + "psr/http-message": "^1.0" + }, + "require-dev": { + "adlawson/timezone": "~1.0", + "fabpot/php-cs-fixer": "~0.5", + "mockery/mockery": "~0.9", + "phpunit/phpunit": "~4.3" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "Graze\\GuzzleHttp\\JsonRpc\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graze tech team", + "homepage": "https://github.com/graze/guzzle-jsonrpc/graphs/contributors" + } + ], + "description": "JSON-RPC 2.0 client for Guzzle", + "homepage": "https://github.com/graze/guzzle-jsonrpc", + "keywords": [ + "Guzzle", + "guzzlehttp", + "http", + "json", + "json-rpc", + "jsonrpc", + "ring", + "rpc" + ], + "support": { + "issues": "https://github.com/graze/guzzle-jsonrpc/issues", + "source": "https://github.com/graze/guzzle-jsonrpc/tree/master" + }, + "time": "2016-02-16T15:18:21+00:00" + }, { "name": "guzzlehttp/guzzle", "version": "6.5.5", @@ -2068,6 +2364,67 @@ ], "time": "2021-10-01T21:08:31+00:00" }, + { + "name": "mtdowling/jmespath.php", + "version": "2.6.1", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/9b87907a81b87bc76d19a7fb2d61e61486ee9edb", + "reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^1.4 || ^2.0", + "phpunit/phpunit": "^4.8.36 || ^7.5.15" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-4": { + "JmesPath\\": "src/" + }, + "files": [ + "src/JmesPath.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.6.1" + }, + "time": "2021-06-14T00:11:39+00:00" + }, { "name": "nette/utils", "version": "v3.2.6", @@ -2153,6 +2510,59 @@ }, "time": "2021-11-24T15:47:23+00:00" }, + { + "name": "pear/math_biginteger", + "version": "v1.0.3", + "source": { + "type": "git", + "url": "https://github.com/pear/Math_BigInteger.git", + "reference": "33d4357543037a458fad3e8c837a01b93104e592" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pear/Math_BigInteger/zipball/33d4357543037a458fad3e8c837a01b93104e592", + "reference": "33d4357543037a458fad3e8c837a01b93104e592", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "php": ">=4.2.0" + }, + "suggest": { + "ext-bcmath": "Allows using the BCMath extension internally for computation. Faster than native implementation.", + "ext-gmp": "Allows using the GNU Multiple Precision extension internally for computation. If you are doing a lot of computation this is the recommended extension." + }, + "type": "library", + "autoload": { + "psr-0": { + "Math_": "./" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net" + } + ], + "description": "Pure-PHP arbitrary precission integer arithmetic library. If GMP or BCMath are available they are used.", + "homepage": "https://github.com/pear/Math_BigInteger", + "keywords": [ + "arbitrary", + "bcmath", + "gmp", + "integer", + "precision" + ], + "support": { + "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Math_BigInteger", + "source": "https://github.com/pear/Math_BigInteger" + }, + "time": "2016-04-12T05:46:52+00:00" + }, { "name": "phpdocumentor/reflection-common", "version": "2.2.0", @@ -2265,16 +2675,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.5.1", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae" + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae", - "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706", + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706", "shasum": "" }, "require": { @@ -2309,118 +2719,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1" - }, - "time": "2021-10-02T14:08:47+00:00" - }, - { - "name": "phpseclib/phpseclib", - "version": "2.0.35", - "source": { - "type": "git", - "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "4e16cf3f5f927a7d3f5317820af795c0366c0420" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/4e16cf3f5f927a7d3f5317820af795c0366c0420", - "reference": "4e16cf3f5f927a7d3f5317820af795c0366c0420", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phing/phing": "~2.7", - "phpunit/phpunit": "^4.8.35|^5.7|^6.0|^9.4", - "squizlabs/php_codesniffer": "~2.0" - }, - "suggest": { - "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", - "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", - "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", - "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." - }, - "type": "library", - "autoload": { - "files": [ - "phpseclib/bootstrap.php" - ], - "psr-4": { - "phpseclib\\": "phpseclib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jim Wigginton", - "email": "terrafrost@php.net", - "role": "Lead Developer" - }, - { - "name": "Patrick Monnerat", - "email": "pm@datasphere.ch", - "role": "Developer" - }, - { - "name": "Andreas Fischer", - "email": "bantu@phpbb.com", - "role": "Developer" - }, - { - "name": "Hans-Jürgen Petrich", - "email": "petrich@tronic-media.com", - "role": "Developer" - }, - { - "name": "Graham Campbell", - "email": "graham@alt-three.com", - "role": "Developer" - } - ], - "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", - "homepage": "http://phpseclib.sourceforge.net", - "keywords": [ - "BigInteger", - "aes", - "asn.1", - "asn1", - "blowfish", - "crypto", - "cryptography", - "encryption", - "rsa", - "security", - "sftp", - "signature", - "signing", - "ssh", - "twofish", - "x.509", - "x509" - ], - "support": { - "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/2.0.35" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0" }, - "funding": [ - { - "url": "https://github.com/terrafrost", - "type": "github" - }, - { - "url": "https://www.patreon.com/phpseclib", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", - "type": "tidelift" - } - ], - "time": "2021-11-28T23:30:39+00:00" + "time": "2022-01-04T19:58:01+00:00" }, { "name": "phpstan/phpdoc-parser", @@ -2818,53 +3119,6 @@ }, "time": "2019-03-08T08:55:37+00:00" }, - { - "name": "sc0vu/web3.php", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/sc0Vu/web3.php.git", - "reference": "d69ce96a646df1bd07e3f21879ce25c114d21634" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sc0Vu/web3.php/zipball/d69ce96a646df1bd07e3f21879ce25c114d21634", - "reference": "d69ce96a646df1bd07e3f21879ce25c114d21634", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "guzzlehttp/guzzle": "~6.0", - "kornrunner/keccak": "~1.0", - "php": "^7.1", - "phpseclib/phpseclib": "~2.0.11" - }, - "require-dev": { - "phpunit/phpunit": "~6.0" - }, - "default-branch": true, - "type": "library", - "autoload": { - "psr-4": { - "Web3\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "sc0Vu", - "email": "alk03073135@gmail.com" - } - ], - "description": "Ethereum web3 interface.", - "support": { - "source": "https://github.com/sc0Vu/web3.php/tree/master" - }, - "time": "2019-10-03T14:41:19+00:00" - }, { "name": "sensio/framework-extra-bundle", "version": "v6.2.5", @@ -2943,6 +3197,153 @@ }, "time": "2022-01-02T16:55:10+00:00" }, + { + "name": "simplito/bigint-wrapper-php", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/simplito/bigint-wrapper-php.git", + "reference": "cf21ec76d33f103add487b3eadbd9f5033a25930" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/simplito/bigint-wrapper-php/zipball/cf21ec76d33f103add487b3eadbd9f5033a25930", + "reference": "cf21ec76d33f103add487b3eadbd9f5033a25930", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "BI\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Simplito Team", + "email": "s.smyczynski@simplito.com", + "homepage": "https://simplito.com" + } + ], + "description": "Common interface for php_gmp and php_bcmath modules", + "support": { + "issues": "https://github.com/simplito/bigint-wrapper-php/issues", + "source": "https://github.com/simplito/bigint-wrapper-php/tree/1.0.0" + }, + "time": "2018-02-27T12:38:08+00:00" + }, + { + "name": "simplito/bn-php", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/simplito/bn-php.git", + "reference": "e852fcd27e4acbc32459606d7606e45a85e42465" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/simplito/bn-php/zipball/e852fcd27e4acbc32459606d7606e45a85e42465", + "reference": "e852fcd27e4acbc32459606d7606e45a85e42465", + "shasum": "" + }, + "require": { + "simplito/bigint-wrapper-php": "~1.0.0" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "BN\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Simplito Team", + "email": "s.smyczynski@simplito.com", + "homepage": "https://simplito.com" + } + ], + "description": "Big number implementation compatible with bn.js", + "support": { + "issues": "https://github.com/simplito/bn-php/issues", + "source": "https://github.com/simplito/bn-php/tree/1.1.2" + }, + "time": "2018-04-12T11:07:43+00:00" + }, + { + "name": "simplito/elliptic-php", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/simplito/elliptic-php.git", + "reference": "18a72b837b845bf9a2ad2c0050eaf864a22b7550" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/simplito/elliptic-php/zipball/18a72b837b845bf9a2ad2c0050eaf864a22b7550", + "reference": "18a72b837b845bf9a2ad2c0050eaf864a22b7550", + "shasum": "" + }, + "require": { + "ext-gmp": "*", + "simplito/bn-php": "~1.1.0" + }, + "require-dev": { + "phpbench/phpbench": "@dev", + "phpunit/phpunit": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Elliptic\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Simplito Team", + "email": "s.smyczynski@simplito.com", + "homepage": "https://simplito.com" + } + ], + "description": "Fast elliptic curve cryptography", + "homepage": "https://github.com/simplito/elliptic-php", + "keywords": [ + "Curve25519", + "ECDSA", + "Ed25519", + "EdDSA", + "cryptography", + "curve", + "curve25519-weier", + "ecc", + "ecdh", + "elliptic", + "nistp192", + "nistp224", + "nistp256", + "nistp384", + "nistp521", + "secp256k1" + ], + "support": { + "issues": "https://github.com/simplito/elliptic-php/issues", + "source": "https://github.com/simplito/elliptic-php/tree/1.0.9" + }, + "time": "2021-10-19T08:42:33+00:00" + }, { "name": "symfony/apache-pack", "version": "v1.0.1", @@ -3488,25 +3889,25 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.0.0", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced" + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/c726b64c1ccfe2896cb7df2e1331c357ad1c8ced", - "reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -3535,7 +3936,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.0" }, "funding": [ { @@ -3551,7 +3952,7 @@ "type": "tidelift" } ], - "time": "2021-11-01T23:48:49+00:00" + "time": "2021-07-12T14:48:14+00:00" }, { "name": "symfony/doctrine-bridge", @@ -5488,16 +5889,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.23.1", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "16880ba9c5ebe3642d1995ab866db29270b36535" + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/16880ba9c5ebe3642d1995ab866db29270b36535", - "reference": "16880ba9c5ebe3642d1995ab866db29270b36535", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", "shasum": "" }, "require": { @@ -5549,7 +5950,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.1" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.24.0" }, "funding": [ { @@ -5565,20 +5966,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T12:26:48+00:00" + "time": "2021-11-23T21:10:46+00:00" }, { "name": "symfony/polyfill-intl-icu", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-icu.git", - "reference": "4a80a521d6176870b6445cfb469c130f9cae1dda" + "reference": "c023a439b8551e320cc3c8433b198e408a623af1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/4a80a521d6176870b6445cfb469c130f9cae1dda", - "reference": "4a80a521d6176870b6445cfb469c130f9cae1dda", + "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/c023a439b8551e320cc3c8433b198e408a623af1", + "reference": "c023a439b8551e320cc3c8433b198e408a623af1", "shasum": "" }, "require": { @@ -5636,7 +6037,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.24.0" }, "funding": [ { @@ -5652,20 +6053,20 @@ "type": "tidelift" } ], - "time": "2021-05-24T10:04:56+00:00" + "time": "2021-10-26T17:16:04+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65" + "reference": "749045c69efb97c70d25d7463abba812e91f3a44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65", - "reference": "65bd267525e82759e7d8c4e8ceea44f398838e65", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/749045c69efb97c70d25d7463abba812e91f3a44", + "reference": "749045c69efb97c70d25d7463abba812e91f3a44", "shasum": "" }, "require": { @@ -5723,7 +6124,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.24.0" }, "funding": [ { @@ -5739,11 +6140,11 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:27:20+00:00" + "time": "2021-09-14T14:02:44+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -5807,7 +6208,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.24.0" }, "funding": [ { @@ -5827,21 +6228,24 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.23.1", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6" + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6", - "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-mbstring": "*" + }, "suggest": { "ext-mbstring": "For best performance" }, @@ -5887,7 +6291,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0" }, "funding": [ { @@ -5903,20 +6307,20 @@ "type": "tidelift" } ], - "time": "2021-05-27T12:26:48+00:00" + "time": "2021-11-30T18:21:41+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010" + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fba8933c384d6476ab14fb7b8526e5287ca7e010", - "reference": "fba8933c384d6476ab14fb7b8526e5287ca7e010", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", "shasum": "" }, "require": { @@ -5966,7 +6370,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.24.0" }, "funding": [ { @@ -5982,20 +6386,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-06-05T21:20:04+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.23.1", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be" + "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be", - "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/57b712b08eddb97c762a8caa32c84e037892d2e9", + "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9", "shasum": "" }, "require": { @@ -6049,7 +6453,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.24.0" }, "funding": [ { @@ -6065,20 +6469,20 @@ "type": "tidelift" } ], - "time": "2021-07-28T13:41:28+00:00" + "time": "2021-09-13T13:58:33+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "e66119f3de95efc359483f810c4c3e6436279436" + "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436", - "reference": "e66119f3de95efc359483f810c4c3e6436279436", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", + "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", "shasum": "" }, "require": { @@ -6128,7 +6532,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.24.0" }, "funding": [ { @@ -6144,7 +6548,7 @@ "type": "tidelift" } ], - "time": "2021-05-21T13:25:03+00:00" + "time": "2021-09-13T13:58:11+00:00" }, { "name": "symfony/process", @@ -7138,21 +7542,22 @@ }, { "name": "symfony/service-contracts", - "version": "v2.4.1", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "d664541b99d6fb0247ec5ff32e87238582236204" + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d664541b99d6fb0247ec5ff32e87238582236204", - "reference": "d664541b99d6fb0247ec5ff32e87238582236204", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/container": "^1.1" + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -7163,7 +7568,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -7200,7 +7605,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.4.1" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.0" }, "funding": [ { @@ -7216,7 +7621,7 @@ "type": "tidelift" } ], - "time": "2021-11-04T16:37:19+00:00" + "time": "2021-11-04T16:48:04+00:00" }, { "name": "symfony/stopwatch", @@ -8809,16 +9214,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.3.0", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "ffc5aee6019eeae4ea618d97dd290ab95e77be59" + "reference": "151a51f6149855785fbd883e79768c0abc96b75f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ffc5aee6019eeae4ea618d97dd290ab95e77be59", - "reference": "ffc5aee6019eeae4ea618d97dd290ab95e77be59", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/151a51f6149855785fbd883e79768c0abc96b75f", + "reference": "151a51f6149855785fbd883e79768c0abc96b75f", "shasum": "" }, "require": { @@ -8849,7 +9254,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.3.0" + "source": "https://github.com/phpstan/phpstan/tree/1.3.3" }, "funding": [ { @@ -8869,7 +9274,7 @@ "type": "tidelift" } ], - "time": "2021-12-29T17:03:31+00:00" + "time": "2022-01-07T09:49:03+00:00" }, { "name": "phpunit/php-code-coverage", @@ -9294,16 +9699,16 @@ }, { "name": "rector/rector", - "version": "0.12.10", + "version": "0.12.12", "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "8c823197becb3905e42b9d7f7849f1174e8b47cf" + "reference": "efcc6f135a76bfd031c31fc182ce7a6fd02b3ce5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/8c823197becb3905e42b9d7f7849f1174e8b47cf", - "reference": "8c823197becb3905e42b9d7f7849f1174e8b47cf", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/efcc6f135a76bfd031c31fc182ce7a6fd02b3ce5", + "reference": "efcc6f135a76bfd031c31fc182ce7a6fd02b3ce5", "shasum": "" }, "require": { @@ -9342,7 +9747,7 @@ "description": "Prefixed and PHP 7.1 downgraded version of rector/rector", "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/0.12.10" + "source": "https://github.com/rectorphp/rector/tree/0.12.12" }, "funding": [ { @@ -9350,7 +9755,7 @@ "type": "github" } ], - "time": "2021-12-31T12:57:22+00:00" + "time": "2022-01-07T16:49:17+00:00" }, { "name": "sebastian/cli-parser", @@ -10861,16 +11266,16 @@ }, { "name": "symplify/astral", - "version": "10.0.8", + "version": "10.0.9", "source": { "type": "git", "url": "https://github.com/symplify/astral.git", - "reference": "6316303eb56640bdfda641839d013d01e8b3fc7b" + "reference": "c3c36ce495fa715822fe58a426d1dbf119435724" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/astral/zipball/6316303eb56640bdfda641839d013d01e8b3fc7b", - "reference": "6316303eb56640bdfda641839d013d01e8b3fc7b", + "url": "https://api.github.com/repos/symplify/astral/zipball/c3c36ce495fa715822fe58a426d1dbf119435724", + "reference": "c3c36ce495fa715822fe58a426d1dbf119435724", "shasum": "" }, "require": { @@ -10879,44 +11284,44 @@ "php": ">=8.0", "phpstan/phpstan": "^1.3", "symfony/dependency-injection": "^5.4|^6.0", - "symplify/package-builder": "^10.0.8", - "symplify/smart-file-system": "^10.0.8", - "symplify/symplify-kernel": "^10.0.8" + "symplify/package-builder": "^10.0.9", + "symplify/smart-file-system": "^10.0.9", + "symplify/symplify-kernel": "^10.0.9" }, "conflict": { - "symplify/amnesia": "<10.0.8", - "symplify/autowire-array-parameter": "<10.0.8", - "symplify/coding-standard": "<10.0.8", - "symplify/composer-json-manipulator": "<10.0.8", - "symplify/config-transformer": "<10.0.8", - "symplify/console-color-diff": "<10.0.8", - "symplify/easy-ci": "<10.0.8", - "symplify/easy-coding-standard": "<10.0.8", - "symplify/easy-parallel": "<10.0.8", - "symplify/easy-testing": "<10.0.8", - "symplify/git-wrapper": "<10.0.8", - "symplify/latte-phpstan-compiler": "<10.0.8", - "symplify/markdown-diff": "<10.0.8", - "symplify/monorepo-builder": "<10.0.8", - "symplify/neon-config-dumper": "<10.0.8", - "symplify/php-config-printer": "<10.0.8", - "symplify/phpstan-extensions": "<10.0.8", - "symplify/phpstan-latte-rules": "<10.0.8", - "symplify/phpstan-rules": "<10.0.8", - "symplify/rule-doc-generator": "<10.0.8", - "symplify/rule-doc-generator-contracts": "<10.0.8", - "symplify/simple-php-doc-parser": "<10.0.8", - "symplify/skipper": "<10.0.8", + "symplify/amnesia": "<10.0.9", + "symplify/autowire-array-parameter": "<10.0.9", + "symplify/coding-standard": "<10.0.9", + "symplify/composer-json-manipulator": "<10.0.9", + "symplify/config-transformer": "<10.0.9", + "symplify/console-color-diff": "<10.0.9", + "symplify/easy-ci": "<10.0.9", + "symplify/easy-coding-standard": "<10.0.9", + "symplify/easy-parallel": "<10.0.9", + "symplify/easy-testing": "<10.0.9", + "symplify/git-wrapper": "<10.0.9", + "symplify/latte-phpstan-compiler": "<10.0.9", + "symplify/markdown-diff": "<10.0.9", + "symplify/monorepo-builder": "<10.0.9", + "symplify/neon-config-dumper": "<10.0.9", + "symplify/php-config-printer": "<10.0.9", + "symplify/phpstan-extensions": "<10.0.9", + "symplify/phpstan-latte-rules": "<10.0.9", + "symplify/phpstan-rules": "<10.0.9", + "symplify/rule-doc-generator": "<10.0.9", + "symplify/rule-doc-generator-contracts": "<10.0.9", + "symplify/simple-php-doc-parser": "<10.0.9", + "symplify/skipper": "<10.0.9", "symplify/smart-file-system": "<9.4.70", - "symplify/symfony-php-config": "<10.0.8", - "symplify/symfony-static-dumper": "<10.0.8", + "symplify/symfony-php-config": "<10.0.9", + "symplify/symfony-static-dumper": "<10.0.9", "symplify/symplify-kernel": "<9.4.70", - "symplify/template-phpstan-compiler": "<10.0.8", - "symplify/vendor-patches": "<10.0.8" + "symplify/template-phpstan-compiler": "<10.0.9", + "symplify/vendor-patches": "<10.0.9" }, "require-dev": { "phpunit/phpunit": "^9.5", - "symplify/easy-testing": "^10.0.8" + "symplify/easy-testing": "^10.0.9" }, "type": "phpstan-extension", "extra": { @@ -10940,7 +11345,7 @@ ], "description": "Toolking for smart daily work with AST", "support": { - "source": "https://github.com/symplify/astral/tree/10.0.8" + "source": "https://github.com/symplify/astral/tree/10.0.9" }, "funding": [ { @@ -10952,58 +11357,58 @@ "type": "github" } ], - "time": "2021-12-31T12:13:55+00:00" + "time": "2022-01-07T14:33:38+00:00" }, { "name": "symplify/autowire-array-parameter", - "version": "10.0.8", + "version": "10.0.9", "source": { "type": "git", "url": "https://github.com/symplify/autowire-array-parameter.git", - "reference": "0f60d272ec76b97322de0dd57f27fc53cb4b9ad8" + "reference": "90c80bd40ec4be096e8d268ecd4bbf43c54c6fa1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/autowire-array-parameter/zipball/0f60d272ec76b97322de0dd57f27fc53cb4b9ad8", - "reference": "0f60d272ec76b97322de0dd57f27fc53cb4b9ad8", + "url": "https://api.github.com/repos/symplify/autowire-array-parameter/zipball/90c80bd40ec4be096e8d268ecd4bbf43c54c6fa1", + "reference": "90c80bd40ec4be096e8d268ecd4bbf43c54c6fa1", "shasum": "" }, "require": { "nette/utils": "^3.2", "php": ">=8.0", "symfony/dependency-injection": "^5.4|^6.0", - "symplify/package-builder": "^10.0.8" + "symplify/package-builder": "^10.0.9" }, "conflict": { - "symplify/amnesia": "<10.0.8", - "symplify/astral": "<10.0.8", - "symplify/coding-standard": "<10.0.8", - "symplify/composer-json-manipulator": "<10.0.8", - "symplify/config-transformer": "<10.0.8", - "symplify/console-color-diff": "<10.0.8", - "symplify/easy-ci": "<10.0.8", - "symplify/easy-coding-standard": "<10.0.8", - "symplify/easy-parallel": "<10.0.8", - "symplify/easy-testing": "<10.0.8", - "symplify/git-wrapper": "<10.0.8", - "symplify/latte-phpstan-compiler": "<10.0.8", - "symplify/markdown-diff": "<10.0.8", - "symplify/monorepo-builder": "<10.0.8", - "symplify/neon-config-dumper": "<10.0.8", - "symplify/php-config-printer": "<10.0.8", - "symplify/phpstan-extensions": "<10.0.8", - "symplify/phpstan-latte-rules": "<10.0.8", - "symplify/phpstan-rules": "<10.0.8", - "symplify/rule-doc-generator": "<10.0.8", - "symplify/rule-doc-generator-contracts": "<10.0.8", - "symplify/simple-php-doc-parser": "<10.0.8", - "symplify/skipper": "<10.0.8", - "symplify/smart-file-system": "<10.0.8", - "symplify/symfony-php-config": "<10.0.8", - "symplify/symfony-static-dumper": "<10.0.8", - "symplify/symplify-kernel": "<10.0.8", - "symplify/template-phpstan-compiler": "<10.0.8", - "symplify/vendor-patches": "<10.0.8" + "symplify/amnesia": "<10.0.9", + "symplify/astral": "<10.0.9", + "symplify/coding-standard": "<10.0.9", + "symplify/composer-json-manipulator": "<10.0.9", + "symplify/config-transformer": "<10.0.9", + "symplify/console-color-diff": "<10.0.9", + "symplify/easy-ci": "<10.0.9", + "symplify/easy-coding-standard": "<10.0.9", + "symplify/easy-parallel": "<10.0.9", + "symplify/easy-testing": "<10.0.9", + "symplify/git-wrapper": "<10.0.9", + "symplify/latte-phpstan-compiler": "<10.0.9", + "symplify/markdown-diff": "<10.0.9", + "symplify/monorepo-builder": "<10.0.9", + "symplify/neon-config-dumper": "<10.0.9", + "symplify/php-config-printer": "<10.0.9", + "symplify/phpstan-extensions": "<10.0.9", + "symplify/phpstan-latte-rules": "<10.0.9", + "symplify/phpstan-rules": "<10.0.9", + "symplify/rule-doc-generator": "<10.0.9", + "symplify/rule-doc-generator-contracts": "<10.0.9", + "symplify/simple-php-doc-parser": "<10.0.9", + "symplify/skipper": "<10.0.9", + "symplify/smart-file-system": "<10.0.9", + "symplify/symfony-php-config": "<10.0.9", + "symplify/symfony-static-dumper": "<10.0.9", + "symplify/symplify-kernel": "<10.0.9", + "symplify/template-phpstan-compiler": "<10.0.9", + "symplify/vendor-patches": "<10.0.9" }, "require-dev": { "phpunit/phpunit": "^9.5" @@ -11025,7 +11430,7 @@ ], "description": "Autowire array parameters for your Symfony applications", "support": { - "source": "https://github.com/symplify/autowire-array-parameter/tree/10.0.8" + "source": "https://github.com/symplify/autowire-array-parameter/tree/10.0.9" }, "funding": [ { @@ -11037,20 +11442,20 @@ "type": "github" } ], - "time": "2021-12-31T12:14:00+00:00" + "time": "2022-01-07T14:33:38+00:00" }, { "name": "symplify/composer-json-manipulator", - "version": "10.0.8", + "version": "10.0.9", "source": { "type": "git", "url": "https://github.com/symplify/composer-json-manipulator.git", - "reference": "c9e1e123c5a5601fb73436e466794640d5830de6" + "reference": "8b9b910e38d025eede81acafeed9032aea333a1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/composer-json-manipulator/zipball/c9e1e123c5a5601fb73436e466794640d5830de6", - "reference": "c9e1e123c5a5601fb73436e466794640d5830de6", + "url": "https://api.github.com/repos/symplify/composer-json-manipulator/zipball/8b9b910e38d025eede81acafeed9032aea333a1b", + "reference": "8b9b910e38d025eede81acafeed9032aea333a1b", "shasum": "" }, "require": { @@ -11059,39 +11464,39 @@ "symfony/config": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", "symfony/filesystem": "^5.4|^6.0", - "symplify/package-builder": "^10.0.8", - "symplify/smart-file-system": "^10.0.8", - "symplify/symplify-kernel": "^10.0.8" + "symplify/package-builder": "^10.0.9", + "symplify/smart-file-system": "^10.0.9", + "symplify/symplify-kernel": "^10.0.9" }, "conflict": { - "symplify/amnesia": "<10.0.8", - "symplify/astral": "<10.0.8", - "symplify/autowire-array-parameter": "<10.0.8", - "symplify/coding-standard": "<10.0.8", - "symplify/config-transformer": "<10.0.8", - "symplify/console-color-diff": "<10.0.8", - "symplify/easy-ci": "<10.0.8", - "symplify/easy-coding-standard": "<10.0.8", - "symplify/easy-parallel": "<10.0.8", - "symplify/easy-testing": "<10.0.8", - "symplify/git-wrapper": "<10.0.8", - "symplify/latte-phpstan-compiler": "<10.0.8", - "symplify/markdown-diff": "<10.0.8", - "symplify/monorepo-builder": "<10.0.8", - "symplify/neon-config-dumper": "<10.0.8", - "symplify/php-config-printer": "<10.0.8", - "symplify/phpstan-extensions": "<10.0.8", - "symplify/phpstan-latte-rules": "<10.0.8", - "symplify/phpstan-rules": "<10.0.8", - "symplify/rule-doc-generator": "<10.0.8", - "symplify/rule-doc-generator-contracts": "<10.0.8", - "symplify/simple-php-doc-parser": "<10.0.8", - "symplify/skipper": "<10.0.8", - "symplify/symfony-php-config": "<10.0.8", - "symplify/symfony-static-dumper": "<10.0.8", + "symplify/amnesia": "<10.0.9", + "symplify/astral": "<10.0.9", + "symplify/autowire-array-parameter": "<10.0.9", + "symplify/coding-standard": "<10.0.9", + "symplify/config-transformer": "<10.0.9", + "symplify/console-color-diff": "<10.0.9", + "symplify/easy-ci": "<10.0.9", + "symplify/easy-coding-standard": "<10.0.9", + "symplify/easy-parallel": "<10.0.9", + "symplify/easy-testing": "<10.0.9", + "symplify/git-wrapper": "<10.0.9", + "symplify/latte-phpstan-compiler": "<10.0.9", + "symplify/markdown-diff": "<10.0.9", + "symplify/monorepo-builder": "<10.0.9", + "symplify/neon-config-dumper": "<10.0.9", + "symplify/php-config-printer": "<10.0.9", + "symplify/phpstan-extensions": "<10.0.9", + "symplify/phpstan-latte-rules": "<10.0.9", + "symplify/phpstan-rules": "<10.0.9", + "symplify/rule-doc-generator": "<10.0.9", + "symplify/rule-doc-generator-contracts": "<10.0.9", + "symplify/simple-php-doc-parser": "<10.0.9", + "symplify/skipper": "<10.0.9", + "symplify/symfony-php-config": "<10.0.9", + "symplify/symfony-static-dumper": "<10.0.9", "symplify/symplify-kernel": "<9.4.70", - "symplify/template-phpstan-compiler": "<10.0.8", - "symplify/vendor-patches": "<10.0.8" + "symplify/template-phpstan-compiler": "<10.0.9", + "symplify/vendor-patches": "<10.0.9" }, "require-dev": { "phpunit/phpunit": "^9.5" @@ -11113,7 +11518,7 @@ ], "description": "Package to load, merge and save composer.json file(s)", "support": { - "source": "https://github.com/symplify/composer-json-manipulator/tree/10.0.8" + "source": "https://github.com/symplify/composer-json-manipulator/tree/10.0.9" }, "funding": [ { @@ -11125,20 +11530,20 @@ "type": "github" } ], - "time": "2021-12-31T12:14:16+00:00" + "time": "2022-01-07T14:33:48+00:00" }, { "name": "symplify/easy-coding-standard", - "version": "10.0.8", + "version": "10.0.9", "source": { "type": "git", "url": "https://github.com/symplify/easy-coding-standard.git", - "reference": "12ef3b0f500d485e6313926e5f2900a74c578394" + "reference": "f0c71b040655e2780a4b701ecf8027ac8e23eedc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/easy-coding-standard/zipball/12ef3b0f500d485e6313926e5f2900a74c578394", - "reference": "12ef3b0f500d485e6313926e5f2900a74c578394", + "url": "https://api.github.com/repos/symplify/easy-coding-standard/zipball/f0c71b040655e2780a4b701ecf8027ac8e23eedc", + "reference": "f0c71b040655e2780a4b701ecf8027ac8e23eedc", "shasum": "" }, "require": { @@ -11168,7 +11573,7 @@ ], "description": "Prefixed scoped version of ECS package", "support": { - "source": "https://github.com/symplify/easy-coding-standard/tree/10.0.8" + "source": "https://github.com/symplify/easy-coding-standard/tree/10.0.9" }, "funding": [ { @@ -11180,20 +11585,20 @@ "type": "github" } ], - "time": "2021-12-31T12:19:54+00:00" + "time": "2022-01-07T16:01:56+00:00" }, { "name": "symplify/easy-testing", - "version": "10.0.8", + "version": "10.0.9", "source": { "type": "git", "url": "https://github.com/symplify/easy-testing.git", - "reference": "f8e1ffb62c995f8453009cacff81a7189d6328ad" + "reference": "73edf932e40f879eede4e4d6d33b2688122f949a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/easy-testing/zipball/f8e1ffb62c995f8453009cacff81a7189d6328ad", - "reference": "f8e1ffb62c995f8453009cacff81a7189d6328ad", + "url": "https://api.github.com/repos/symplify/easy-testing/zipball/73edf932e40f879eede4e4d6d33b2688122f949a", + "reference": "73edf932e40f879eede4e4d6d33b2688122f949a", "shasum": "" }, "require": { @@ -11202,38 +11607,38 @@ "symfony/console": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", - "symplify/package-builder": "^10.0.8", - "symplify/smart-file-system": "^10.0.8", - "symplify/symplify-kernel": "^10.0.8" + "symplify/package-builder": "^10.0.9", + "symplify/smart-file-system": "^10.0.9", + "symplify/symplify-kernel": "^10.0.9" }, "conflict": { - "symplify/amnesia": "<10.0.8", - "symplify/astral": "<10.0.8", - "symplify/autowire-array-parameter": "<10.0.8", - "symplify/coding-standard": "<10.0.8", - "symplify/composer-json-manipulator": "<10.0.8", - "symplify/config-transformer": "<10.0.8", - "symplify/console-color-diff": "<10.0.8", - "symplify/easy-ci": "<10.0.8", - "symplify/easy-coding-standard": "<10.0.8", - "symplify/easy-parallel": "<10.0.8", - "symplify/git-wrapper": "<10.0.8", - "symplify/latte-phpstan-compiler": "<10.0.8", - "symplify/markdown-diff": "<10.0.8", - "symplify/monorepo-builder": "<10.0.8", - "symplify/neon-config-dumper": "<10.0.8", - "symplify/php-config-printer": "<10.0.8", - "symplify/phpstan-extensions": "<10.0.8", - "symplify/phpstan-latte-rules": "<10.0.8", - "symplify/phpstan-rules": "<10.0.8", - "symplify/rule-doc-generator": "<10.0.8", - "symplify/rule-doc-generator-contracts": "<10.0.8", - "symplify/simple-php-doc-parser": "<10.0.8", - "symplify/skipper": "<10.0.8", - "symplify/symfony-php-config": "<10.0.8", - "symplify/symfony-static-dumper": "<10.0.8", - "symplify/template-phpstan-compiler": "<10.0.8", - "symplify/vendor-patches": "<10.0.8" + "symplify/amnesia": "<10.0.9", + "symplify/astral": "<10.0.9", + "symplify/autowire-array-parameter": "<10.0.9", + "symplify/coding-standard": "<10.0.9", + "symplify/composer-json-manipulator": "<10.0.9", + "symplify/config-transformer": "<10.0.9", + "symplify/console-color-diff": "<10.0.9", + "symplify/easy-ci": "<10.0.9", + "symplify/easy-coding-standard": "<10.0.9", + "symplify/easy-parallel": "<10.0.9", + "symplify/git-wrapper": "<10.0.9", + "symplify/latte-phpstan-compiler": "<10.0.9", + "symplify/markdown-diff": "<10.0.9", + "symplify/monorepo-builder": "<10.0.9", + "symplify/neon-config-dumper": "<10.0.9", + "symplify/php-config-printer": "<10.0.9", + "symplify/phpstan-extensions": "<10.0.9", + "symplify/phpstan-latte-rules": "<10.0.9", + "symplify/phpstan-rules": "<10.0.9", + "symplify/rule-doc-generator": "<10.0.9", + "symplify/rule-doc-generator-contracts": "<10.0.9", + "symplify/simple-php-doc-parser": "<10.0.9", + "symplify/skipper": "<10.0.9", + "symplify/symfony-php-config": "<10.0.9", + "symplify/symfony-static-dumper": "<10.0.9", + "symplify/template-phpstan-compiler": "<10.0.9", + "symplify/vendor-patches": "<10.0.9" }, "require-dev": { "phpunit/phpunit": "^9.5" @@ -11258,7 +11663,7 @@ ], "description": "Testing made easy", "support": { - "source": "https://github.com/symplify/easy-testing/tree/10.0.8" + "source": "https://github.com/symplify/easy-testing/tree/10.0.9" }, "funding": [ { @@ -11270,20 +11675,20 @@ "type": "github" } ], - "time": "2021-12-31T12:14:30+00:00" + "time": "2022-01-07T14:33:51+00:00" }, { "name": "symplify/package-builder", - "version": "10.0.8", + "version": "10.0.9", "source": { "type": "git", "url": "https://github.com/symplify/package-builder.git", - "reference": "5759f551697c368815d21e6531c49276981b8928" + "reference": "23dfbdf01c2e08027e1db0694f1c697c0d4cc72f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/package-builder/zipball/5759f551697c368815d21e6531c49276981b8928", - "reference": "5759f551697c368815d21e6531c49276981b8928", + "url": "https://api.github.com/repos/symplify/package-builder/zipball/23dfbdf01c2e08027e1db0694f1c697c0d4cc72f", + "reference": "23dfbdf01c2e08027e1db0694f1c697c0d4cc72f", "shasum": "" }, "require": { @@ -11294,38 +11699,38 @@ "symfony/console": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", - "symplify/easy-testing": "^10.0.8", - "symplify/symplify-kernel": "^10.0.8" + "symplify/easy-testing": "^10.0.9", + "symplify/symplify-kernel": "^10.0.9" }, "conflict": { - "symplify/amnesia": "<10.0.8", - "symplify/astral": "<10.0.8", - "symplify/autowire-array-parameter": "<10.0.8", - "symplify/coding-standard": "<10.0.8", - "symplify/composer-json-manipulator": "<10.0.8", - "symplify/config-transformer": "<10.0.8", - "symplify/console-color-diff": "<10.0.8", - "symplify/easy-ci": "<10.0.8", - "symplify/easy-coding-standard": "<10.0.8", - "symplify/easy-parallel": "<10.0.8", - "symplify/git-wrapper": "<10.0.8", - "symplify/latte-phpstan-compiler": "<10.0.8", - "symplify/markdown-diff": "<10.0.8", - "symplify/monorepo-builder": "<10.0.8", - "symplify/neon-config-dumper": "<10.0.8", - "symplify/php-config-printer": "<10.0.8", - "symplify/phpstan-extensions": "<10.0.8", - "symplify/phpstan-latte-rules": "<10.0.8", - "symplify/phpstan-rules": "<10.0.8", - "symplify/rule-doc-generator": "<10.0.8", - "symplify/rule-doc-generator-contracts": "<10.0.8", - "symplify/simple-php-doc-parser": "<10.0.8", - "symplify/skipper": "<10.0.8", - "symplify/smart-file-system": "<10.0.8", - "symplify/symfony-php-config": "<10.0.8", - "symplify/symfony-static-dumper": "<10.0.8", - "symplify/template-phpstan-compiler": "<10.0.8", - "symplify/vendor-patches": "<10.0.8" + "symplify/amnesia": "<10.0.9", + "symplify/astral": "<10.0.9", + "symplify/autowire-array-parameter": "<10.0.9", + "symplify/coding-standard": "<10.0.9", + "symplify/composer-json-manipulator": "<10.0.9", + "symplify/config-transformer": "<10.0.9", + "symplify/console-color-diff": "<10.0.9", + "symplify/easy-ci": "<10.0.9", + "symplify/easy-coding-standard": "<10.0.9", + "symplify/easy-parallel": "<10.0.9", + "symplify/git-wrapper": "<10.0.9", + "symplify/latte-phpstan-compiler": "<10.0.9", + "symplify/markdown-diff": "<10.0.9", + "symplify/monorepo-builder": "<10.0.9", + "symplify/neon-config-dumper": "<10.0.9", + "symplify/php-config-printer": "<10.0.9", + "symplify/phpstan-extensions": "<10.0.9", + "symplify/phpstan-latte-rules": "<10.0.9", + "symplify/phpstan-rules": "<10.0.9", + "symplify/rule-doc-generator": "<10.0.9", + "symplify/rule-doc-generator-contracts": "<10.0.9", + "symplify/simple-php-doc-parser": "<10.0.9", + "symplify/skipper": "<10.0.9", + "symplify/smart-file-system": "<10.0.9", + "symplify/symfony-php-config": "<10.0.9", + "symplify/symfony-static-dumper": "<10.0.9", + "symplify/template-phpstan-compiler": "<10.0.9", + "symplify/vendor-patches": "<10.0.9" }, "require-dev": { "phpunit/phpunit": "^9.5" @@ -11347,7 +11752,7 @@ ], "description": "Dependency Injection, Console and Kernel toolkit for Symplify packages.", "support": { - "source": "https://github.com/symplify/package-builder/tree/10.0.8" + "source": "https://github.com/symplify/package-builder/tree/10.0.9" }, "funding": [ { @@ -11359,20 +11764,20 @@ "type": "github" } ], - "time": "2021-12-31T12:15:12+00:00" + "time": "2022-01-07T14:33:57+00:00" }, { "name": "symplify/phpstan-rules", - "version": "10.0.8", + "version": "10.0.9", "source": { "type": "git", "url": "https://github.com/symplify/phpstan-rules.git", - "reference": "6bebb6f0b5ed9ab7c993ecfdff662979c87585a8" + "reference": "306b226b6fd6dc476a7314b80c46409920073534" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/phpstan-rules/zipball/6bebb6f0b5ed9ab7c993ecfdff662979c87585a8", - "reference": "6bebb6f0b5ed9ab7c993ecfdff662979c87585a8", + "url": "https://api.github.com/repos/symplify/phpstan-rules/zipball/306b226b6fd6dc476a7314b80c46409920073534", + "reference": "306b226b6fd6dc476a7314b80c46409920073534", "shasum": "" }, "require": { @@ -11381,47 +11786,47 @@ "php": ">=8.0", "phpstan/phpdoc-parser": "^1.2", "phpstan/phpstan": "^1.3", - "symplify/astral": "^10.0.8", - "symplify/composer-json-manipulator": "^10.0.8", - "symplify/package-builder": "^10.0.8", - "symplify/rule-doc-generator-contracts": "^10.0.8", - "symplify/simple-php-doc-parser": "^10.0.8", - "symplify/smart-file-system": "^10.0.8", + "symplify/astral": "^10.0.9", + "symplify/composer-json-manipulator": "^10.0.9", + "symplify/package-builder": "^10.0.9", + "symplify/rule-doc-generator-contracts": "^10.0.9", + "symplify/simple-php-doc-parser": "^10.0.9", + "symplify/smart-file-system": "^10.0.9", "webmozart/assert": "^1.10" }, "conflict": { - "symplify/amnesia": "<10.0.8", - "symplify/autowire-array-parameter": "<10.0.8", - "symplify/coding-standard": "<10.0.8", - "symplify/config-transformer": "<10.0.8", - "symplify/console-color-diff": "<10.0.8", - "symplify/easy-ci": "<10.0.8", - "symplify/easy-coding-standard": "<10.0.8", - "symplify/easy-parallel": "<10.0.8", - "symplify/easy-testing": "<10.0.8", - "symplify/git-wrapper": "<10.0.8", - "symplify/latte-phpstan-compiler": "<10.0.8", - "symplify/markdown-diff": "<10.0.8", - "symplify/monorepo-builder": "<10.0.8", - "symplify/neon-config-dumper": "<10.0.8", - "symplify/php-config-printer": "<10.0.8", - "symplify/phpstan-extensions": "<10.0.8", - "symplify/phpstan-latte-rules": "<10.0.8", - "symplify/rule-doc-generator": "<10.0.8", - "symplify/skipper": "<10.0.8", - "symplify/symfony-php-config": "<10.0.8", - "symplify/symfony-static-dumper": "<10.0.8", - "symplify/symplify-kernel": "<10.0.8", - "symplify/template-phpstan-compiler": "<10.0.8", - "symplify/vendor-patches": "<10.0.8" + "symplify/amnesia": "<10.0.9", + "symplify/autowire-array-parameter": "<10.0.9", + "symplify/coding-standard": "<10.0.9", + "symplify/config-transformer": "<10.0.9", + "symplify/console-color-diff": "<10.0.9", + "symplify/easy-ci": "<10.0.9", + "symplify/easy-coding-standard": "<10.0.9", + "symplify/easy-parallel": "<10.0.9", + "symplify/easy-testing": "<10.0.9", + "symplify/git-wrapper": "<10.0.9", + "symplify/latte-phpstan-compiler": "<10.0.9", + "symplify/markdown-diff": "<10.0.9", + "symplify/monorepo-builder": "<10.0.9", + "symplify/neon-config-dumper": "<10.0.9", + "symplify/php-config-printer": "<10.0.9", + "symplify/phpstan-extensions": "<10.0.9", + "symplify/phpstan-latte-rules": "<10.0.9", + "symplify/rule-doc-generator": "<10.0.9", + "symplify/skipper": "<10.0.9", + "symplify/symfony-php-config": "<10.0.9", + "symplify/symfony-static-dumper": "<10.0.9", + "symplify/symplify-kernel": "<10.0.9", + "symplify/template-phpstan-compiler": "<10.0.9", + "symplify/vendor-patches": "<10.0.9" }, "require-dev": { "myclabs/php-enum": "^1.8", "phpunit/phpunit": "^9.5", "symfony/framework-bundle": "^5.4|^6.0", - "symplify/easy-testing": "^10.0.8", - "symplify/phpstan-extensions": "^10.0.8", - "symplify/rule-doc-generator": "^10.0.8" + "symplify/easy-testing": "^10.0.9", + "symplify/phpstan-extensions": "^10.0.9", + "symplify/rule-doc-generator": "^10.0.9" }, "type": "phpstan-extension", "extra": { @@ -11452,7 +11857,7 @@ ], "description": "Set of Symplify rules for PHPStan", "support": { - "source": "https://github.com/symplify/phpstan-rules/tree/10.0.8" + "source": "https://github.com/symplify/phpstan-rules/tree/10.0.9" }, "funding": [ { @@ -11464,20 +11869,20 @@ "type": "github" } ], - "time": "2021-12-31T12:15:33+00:00" + "time": "2022-01-07T14:34:15+00:00" }, { "name": "symplify/rule-doc-generator-contracts", - "version": "10.0.8", + "version": "10.0.9", "source": { "type": "git", "url": "https://github.com/symplify/rule-doc-generator-contracts.git", - "reference": "aa66737a04c5717805112e55b5a62a05e57a8606" + "reference": "5be94d236a216630c23fcfce873964c4aafb5420" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/rule-doc-generator-contracts/zipball/aa66737a04c5717805112e55b5a62a05e57a8606", - "reference": "aa66737a04c5717805112e55b5a62a05e57a8606", + "url": "https://api.github.com/repos/symplify/rule-doc-generator-contracts/zipball/5be94d236a216630c23fcfce873964c4aafb5420", + "reference": "5be94d236a216630c23fcfce873964c4aafb5420", "shasum": "" }, "require": { @@ -11485,36 +11890,36 @@ "php": ">=8.0" }, "conflict": { - "symplify/amnesia": "<10.0.8", - "symplify/astral": "<10.0.8", - "symplify/autowire-array-parameter": "<10.0.8", - "symplify/coding-standard": "<10.0.8", - "symplify/composer-json-manipulator": "<10.0.8", - "symplify/config-transformer": "<10.0.8", - "symplify/console-color-diff": "<10.0.8", - "symplify/easy-ci": "<10.0.8", - "symplify/easy-coding-standard": "<10.0.8", - "symplify/easy-parallel": "<10.0.8", - "symplify/easy-testing": "<10.0.8", - "symplify/git-wrapper": "<10.0.8", - "symplify/latte-phpstan-compiler": "<10.0.8", - "symplify/markdown-diff": "<10.0.8", - "symplify/monorepo-builder": "<10.0.8", - "symplify/neon-config-dumper": "<10.0.8", - "symplify/package-builder": "<10.0.8", - "symplify/php-config-printer": "<10.0.8", - "symplify/phpstan-extensions": "<10.0.8", - "symplify/phpstan-latte-rules": "<10.0.8", - "symplify/phpstan-rules": "<10.0.8", - "symplify/rule-doc-generator": "<10.0.8", - "symplify/simple-php-doc-parser": "<10.0.8", - "symplify/skipper": "<10.0.8", - "symplify/smart-file-system": "<10.0.8", - "symplify/symfony-php-config": "<10.0.8", - "symplify/symfony-static-dumper": "<10.0.8", - "symplify/symplify-kernel": "<10.0.8", - "symplify/template-phpstan-compiler": "<10.0.8", - "symplify/vendor-patches": "<10.0.8" + "symplify/amnesia": "<10.0.9", + "symplify/astral": "<10.0.9", + "symplify/autowire-array-parameter": "<10.0.9", + "symplify/coding-standard": "<10.0.9", + "symplify/composer-json-manipulator": "<10.0.9", + "symplify/config-transformer": "<10.0.9", + "symplify/console-color-diff": "<10.0.9", + "symplify/easy-ci": "<10.0.9", + "symplify/easy-coding-standard": "<10.0.9", + "symplify/easy-parallel": "<10.0.9", + "symplify/easy-testing": "<10.0.9", + "symplify/git-wrapper": "<10.0.9", + "symplify/latte-phpstan-compiler": "<10.0.9", + "symplify/markdown-diff": "<10.0.9", + "symplify/monorepo-builder": "<10.0.9", + "symplify/neon-config-dumper": "<10.0.9", + "symplify/package-builder": "<10.0.9", + "symplify/php-config-printer": "<10.0.9", + "symplify/phpstan-extensions": "<10.0.9", + "symplify/phpstan-latte-rules": "<10.0.9", + "symplify/phpstan-rules": "<10.0.9", + "symplify/rule-doc-generator": "<10.0.9", + "symplify/simple-php-doc-parser": "<10.0.9", + "symplify/skipper": "<10.0.9", + "symplify/smart-file-system": "<10.0.9", + "symplify/symfony-php-config": "<10.0.9", + "symplify/symfony-static-dumper": "<10.0.9", + "symplify/symplify-kernel": "<10.0.9", + "symplify/template-phpstan-compiler": "<10.0.9", + "symplify/vendor-patches": "<10.0.9" }, "type": "library", "extra": { @@ -11533,7 +11938,7 @@ ], "description": "Contracts for production code of RuleDocGenerator", "support": { - "source": "https://github.com/symplify/rule-doc-generator-contracts/tree/10.0.8" + "source": "https://github.com/symplify/rule-doc-generator-contracts/tree/10.0.9" }, "funding": [ { @@ -11545,20 +11950,20 @@ "type": "github" } ], - "time": "2021-12-31T12:15:26+00:00" + "time": "2022-01-07T14:34:17+00:00" }, { "name": "symplify/simple-php-doc-parser", - "version": "10.0.8", + "version": "10.0.9", "source": { "type": "git", "url": "https://github.com/symplify/simple-php-doc-parser.git", - "reference": "d1fdd95d4030f2fe754f414dd93967237a597090" + "reference": "e6a65b92b46ea0c8cc939f6613d1c33e92656d03" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/simple-php-doc-parser/zipball/d1fdd95d4030f2fe754f414dd93967237a597090", - "reference": "d1fdd95d4030f2fe754f414dd93967237a597090", + "url": "https://api.github.com/repos/symplify/simple-php-doc-parser/zipball/e6a65b92b46ea0c8cc939f6613d1c33e92656d03", + "reference": "e6a65b92b46ea0c8cc939f6613d1c33e92656d03", "shasum": "" }, "require": { @@ -11566,42 +11971,42 @@ "phpstan/phpdoc-parser": "^1.2", "symfony/config": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", - "symplify/package-builder": "^10.0.8" + "symplify/package-builder": "^10.0.9" }, "conflict": { - "symplify/amnesia": "<10.0.8", - "symplify/astral": "<10.0.8", - "symplify/autowire-array-parameter": "<10.0.8", - "symplify/coding-standard": "<10.0.8", - "symplify/composer-json-manipulator": "<10.0.8", - "symplify/config-transformer": "<10.0.8", - "symplify/console-color-diff": "<10.0.8", - "symplify/easy-ci": "<10.0.8", - "symplify/easy-coding-standard": "<10.0.8", - "symplify/easy-parallel": "<10.0.8", - "symplify/easy-testing": "<10.0.8", - "symplify/git-wrapper": "<10.0.8", - "symplify/latte-phpstan-compiler": "<10.0.8", - "symplify/markdown-diff": "<10.0.8", - "symplify/monorepo-builder": "<10.0.8", - "symplify/neon-config-dumper": "<10.0.8", - "symplify/php-config-printer": "<10.0.8", - "symplify/phpstan-extensions": "<10.0.8", - "symplify/phpstan-latte-rules": "<10.0.8", - "symplify/phpstan-rules": "<10.0.8", - "symplify/rule-doc-generator": "<10.0.8", - "symplify/rule-doc-generator-contracts": "<10.0.8", - "symplify/skipper": "<10.0.8", - "symplify/smart-file-system": "<10.0.8", - "symplify/symfony-php-config": "<10.0.8", - "symplify/symfony-static-dumper": "<10.0.8", - "symplify/symplify-kernel": "<10.0.8", - "symplify/template-phpstan-compiler": "<10.0.8", - "symplify/vendor-patches": "<10.0.8" + "symplify/amnesia": "<10.0.9", + "symplify/astral": "<10.0.9", + "symplify/autowire-array-parameter": "<10.0.9", + "symplify/coding-standard": "<10.0.9", + "symplify/composer-json-manipulator": "<10.0.9", + "symplify/config-transformer": "<10.0.9", + "symplify/console-color-diff": "<10.0.9", + "symplify/easy-ci": "<10.0.9", + "symplify/easy-coding-standard": "<10.0.9", + "symplify/easy-parallel": "<10.0.9", + "symplify/easy-testing": "<10.0.9", + "symplify/git-wrapper": "<10.0.9", + "symplify/latte-phpstan-compiler": "<10.0.9", + "symplify/markdown-diff": "<10.0.9", + "symplify/monorepo-builder": "<10.0.9", + "symplify/neon-config-dumper": "<10.0.9", + "symplify/php-config-printer": "<10.0.9", + "symplify/phpstan-extensions": "<10.0.9", + "symplify/phpstan-latte-rules": "<10.0.9", + "symplify/phpstan-rules": "<10.0.9", + "symplify/rule-doc-generator": "<10.0.9", + "symplify/rule-doc-generator-contracts": "<10.0.9", + "symplify/skipper": "<10.0.9", + "symplify/smart-file-system": "<10.0.9", + "symplify/symfony-php-config": "<10.0.9", + "symplify/symfony-static-dumper": "<10.0.9", + "symplify/symplify-kernel": "<10.0.9", + "symplify/template-phpstan-compiler": "<10.0.9", + "symplify/vendor-patches": "<10.0.9" }, "require-dev": { "phpunit/phpunit": "^9.5", - "symplify/easy-testing": "^10.0.8" + "symplify/easy-testing": "^10.0.9" }, "type": "library", "extra": { @@ -11620,7 +12025,7 @@ ], "description": "Service integration of phpstan/phpdoc-parser, with few extra goodies for practical simple use", "support": { - "source": "https://github.com/symplify/simple-php-doc-parser/tree/10.0.8" + "source": "https://github.com/symplify/simple-php-doc-parser/tree/10.0.9" }, "funding": [ { @@ -11632,20 +12037,20 @@ "type": "github" } ], - "time": "2021-12-31T12:15:32+00:00" + "time": "2022-01-07T14:34:18+00:00" }, { "name": "symplify/smart-file-system", - "version": "10.0.8", + "version": "10.0.9", "source": { "type": "git", "url": "https://github.com/symplify/smart-file-system.git", - "reference": "3332ee2669aeb7670924813fa5a40bcb1927fee8" + "reference": "1c385ee3092f41a3e02e3a22bb2e3c2f7905c327" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/smart-file-system/zipball/3332ee2669aeb7670924813fa5a40bcb1927fee8", - "reference": "3332ee2669aeb7670924813fa5a40bcb1927fee8", + "url": "https://api.github.com/repos/symplify/smart-file-system/zipball/1c385ee3092f41a3e02e3a22bb2e3c2f7905c327", + "reference": "1c385ee3092f41a3e02e3a22bb2e3c2f7905c327", "shasum": "" }, "require": { @@ -11655,36 +12060,36 @@ "symfony/finder": "^5.4|^6.0" }, "conflict": { - "symplify/amnesia": "<10.0.8", - "symplify/astral": "<10.0.8", - "symplify/autowire-array-parameter": "<10.0.8", - "symplify/coding-standard": "<10.0.8", - "symplify/composer-json-manipulator": "<10.0.8", - "symplify/config-transformer": "<10.0.8", - "symplify/console-color-diff": "<10.0.8", - "symplify/easy-ci": "<10.0.8", - "symplify/easy-coding-standard": "<10.0.8", - "symplify/easy-parallel": "<10.0.8", - "symplify/easy-testing": "<10.0.8", - "symplify/git-wrapper": "<10.0.8", - "symplify/latte-phpstan-compiler": "<10.0.8", - "symplify/markdown-diff": "<10.0.8", - "symplify/monorepo-builder": "<10.0.8", - "symplify/neon-config-dumper": "<10.0.8", - "symplify/package-builder": "<10.0.8", - "symplify/php-config-printer": "<10.0.8", - "symplify/phpstan-extensions": "<10.0.8", - "symplify/phpstan-latte-rules": "<10.0.8", - "symplify/phpstan-rules": "<10.0.8", - "symplify/rule-doc-generator": "<10.0.8", - "symplify/rule-doc-generator-contracts": "<10.0.8", - "symplify/simple-php-doc-parser": "<10.0.8", - "symplify/skipper": "<10.0.8", - "symplify/symfony-php-config": "<10.0.8", - "symplify/symfony-static-dumper": "<10.0.8", - "symplify/symplify-kernel": "<10.0.8", - "symplify/template-phpstan-compiler": "<10.0.8", - "symplify/vendor-patches": "<10.0.8" + "symplify/amnesia": "<10.0.9", + "symplify/astral": "<10.0.9", + "symplify/autowire-array-parameter": "<10.0.9", + "symplify/coding-standard": "<10.0.9", + "symplify/composer-json-manipulator": "<10.0.9", + "symplify/config-transformer": "<10.0.9", + "symplify/console-color-diff": "<10.0.9", + "symplify/easy-ci": "<10.0.9", + "symplify/easy-coding-standard": "<10.0.9", + "symplify/easy-parallel": "<10.0.9", + "symplify/easy-testing": "<10.0.9", + "symplify/git-wrapper": "<10.0.9", + "symplify/latte-phpstan-compiler": "<10.0.9", + "symplify/markdown-diff": "<10.0.9", + "symplify/monorepo-builder": "<10.0.9", + "symplify/neon-config-dumper": "<10.0.9", + "symplify/package-builder": "<10.0.9", + "symplify/php-config-printer": "<10.0.9", + "symplify/phpstan-extensions": "<10.0.9", + "symplify/phpstan-latte-rules": "<10.0.9", + "symplify/phpstan-rules": "<10.0.9", + "symplify/rule-doc-generator": "<10.0.9", + "symplify/rule-doc-generator-contracts": "<10.0.9", + "symplify/simple-php-doc-parser": "<10.0.9", + "symplify/skipper": "<10.0.9", + "symplify/symfony-php-config": "<10.0.9", + "symplify/symfony-static-dumper": "<10.0.9", + "symplify/symplify-kernel": "<10.0.9", + "symplify/template-phpstan-compiler": "<10.0.9", + "symplify/vendor-patches": "<10.0.9" }, "require-dev": { "nette/finder": "^2.5", @@ -11707,7 +12112,7 @@ ], "description": "Sanitized FileInfo with safe getRealPath() and other handy methods", "support": { - "source": "https://github.com/symplify/smart-file-system/tree/10.0.8" + "source": "https://github.com/symplify/smart-file-system/tree/10.0.9" }, "funding": [ { @@ -11719,60 +12124,60 @@ "type": "github" } ], - "time": "2021-12-31T12:15:53+00:00" + "time": "2022-01-07T14:34:32+00:00" }, { "name": "symplify/symplify-kernel", - "version": "10.0.8", + "version": "10.0.9", "source": { "type": "git", "url": "https://github.com/symplify/symplify-kernel.git", - "reference": "a9364a5bd2fb7ae38dbec1334efb9791793f75d3" + "reference": "a53e2dcdb0d676550f92ad089234045c7d450421" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/symplify-kernel/zipball/a9364a5bd2fb7ae38dbec1334efb9791793f75d3", - "reference": "a9364a5bd2fb7ae38dbec1334efb9791793f75d3", + "url": "https://api.github.com/repos/symplify/symplify-kernel/zipball/a53e2dcdb0d676550f92ad089234045c7d450421", + "reference": "a53e2dcdb0d676550f92ad089234045c7d450421", "shasum": "" }, "require": { "php": ">=8.0", "symfony/console": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", - "symplify/autowire-array-parameter": "^10.0.8", - "symplify/composer-json-manipulator": "^10.0.8", - "symplify/package-builder": "^10.0.8", - "symplify/smart-file-system": "^10.0.8", - "symplify/symplify-kernel": "^10.0.8", + "symplify/autowire-array-parameter": "^10.0.9", + "symplify/composer-json-manipulator": "^10.0.9", + "symplify/package-builder": "^10.0.9", + "symplify/smart-file-system": "^10.0.9", + "symplify/symplify-kernel": "^10.0.9", "webmozart/assert": "^1.10" }, "conflict": { - "symplify/amnesia": "<10.0.8", - "symplify/astral": "<10.0.8", - "symplify/coding-standard": "<10.0.8", - "symplify/config-transformer": "<10.0.8", - "symplify/console-color-diff": "<10.0.8", - "symplify/easy-ci": "<10.0.8", - "symplify/easy-coding-standard": "<10.0.8", - "symplify/easy-parallel": "<10.0.8", - "symplify/easy-testing": "<10.0.8", - "symplify/git-wrapper": "<10.0.8", - "symplify/latte-phpstan-compiler": "<10.0.8", - "symplify/markdown-diff": "<10.0.8", - "symplify/monorepo-builder": "<10.0.8", - "symplify/neon-config-dumper": "<10.0.8", - "symplify/php-config-printer": "<10.0.8", - "symplify/phpstan-extensions": "<10.0.8", - "symplify/phpstan-latte-rules": "<10.0.8", - "symplify/phpstan-rules": "<10.0.8", - "symplify/rule-doc-generator": "<10.0.8", - "symplify/rule-doc-generator-contracts": "<10.0.8", - "symplify/simple-php-doc-parser": "<10.0.8", - "symplify/skipper": "<10.0.8", - "symplify/symfony-php-config": "<10.0.8", - "symplify/symfony-static-dumper": "<10.0.8", - "symplify/template-phpstan-compiler": "<10.0.8", - "symplify/vendor-patches": "<10.0.8" + "symplify/amnesia": "<10.0.9", + "symplify/astral": "<10.0.9", + "symplify/coding-standard": "<10.0.9", + "symplify/config-transformer": "<10.0.9", + "symplify/console-color-diff": "<10.0.9", + "symplify/easy-ci": "<10.0.9", + "symplify/easy-coding-standard": "<10.0.9", + "symplify/easy-parallel": "<10.0.9", + "symplify/easy-testing": "<10.0.9", + "symplify/git-wrapper": "<10.0.9", + "symplify/latte-phpstan-compiler": "<10.0.9", + "symplify/markdown-diff": "<10.0.9", + "symplify/monorepo-builder": "<10.0.9", + "symplify/neon-config-dumper": "<10.0.9", + "symplify/php-config-printer": "<10.0.9", + "symplify/phpstan-extensions": "<10.0.9", + "symplify/phpstan-latte-rules": "<10.0.9", + "symplify/phpstan-rules": "<10.0.9", + "symplify/rule-doc-generator": "<10.0.9", + "symplify/rule-doc-generator-contracts": "<10.0.9", + "symplify/simple-php-doc-parser": "<10.0.9", + "symplify/skipper": "<10.0.9", + "symplify/symfony-php-config": "<10.0.9", + "symplify/symfony-static-dumper": "<10.0.9", + "symplify/template-phpstan-compiler": "<10.0.9", + "symplify/vendor-patches": "<10.0.9" }, "require-dev": { "phpunit/phpunit": "^9.5" @@ -11794,9 +12199,9 @@ ], "description": "Internal Kernel for Symplify packages", "support": { - "source": "https://github.com/symplify/symplify-kernel/tree/10.0.8" + "source": "https://github.com/symplify/symplify-kernel/tree/10.0.9" }, - "time": "2021-12-31T12:16:01+00:00" + "time": "2022-01-07T14:34:34+00:00" }, { "name": "theseer/tokenizer", @@ -11852,7 +12257,7 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { - "sc0vu/web3.php": 20 + "digitaldonkey/ethereum-php": 20 }, "prefer-stable": true, "prefer-lowest": false, diff --git a/config/services.yaml b/config/services.yaml index 979910e..c32573f 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -5,6 +5,9 @@ # https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration parameters: app.cache_expiration: '%env(int:CACHE_EXPIRATION)%' + app.collection_max_supply: '%env(int:COLLECTION_MAX_SUPPLY)%' + app.collection_assets_extension: '%env(COLLECTION_ASSETS_EXTENSION)%' + app.collection_hidden_asset_extension: '%env(COLLECTION_HIDDEN_ASSET_EXTENSION)%' services: # default configuration for services in *this* file @@ -29,8 +32,30 @@ services: # add more service definitions when explicit configuration is needed # please note that last definitions always *replace* previous ones + file_system_driver.local: + class: App\FilesystemDriver\LocalFilesystemDriver + arguments: + - '%env(resolve:LOCAL_FS_DRIVER_COLLECTION_PATH)%' + - '%app.collection_assets_extension%' + - '%app.collection_hidden_asset_extension%' + + file_system_driver.s3: + class: App\FilesystemDriver\S3FilesystemDriver + arguments: + - '%env(resolve:S3_FS_DRIVER_REGION)%' + - '%env(resolve:S3_FS_DRIVER_ENDPOINT_URL)%' + - '%env(resolve:S3_FS_DRIVER_ACCESS_KEY)%' + - '%env(resolve:S3_FS_DRIVER_SECRET_KEY)%' + - '%env(resolve:S3_FS_DRIVER_BUCKET_NAME)%' + - '%env(resolve:S3_FS_DRIVER_OBJECTS_KEY_PREFIX)%' + - '%app.collection_assets_extension%' + - '%app.collection_hidden_asset_extension%' + + App\Contract\CollectionFilesystemDriverInterface: '@file_system_driver.s3' + App\Service\CollectionManager: arguments: + - '%app.collection_max_supply%' - !tagged_iterator app.metadata_updater total_supply_provider.env_var: @@ -49,4 +74,4 @@ services: - '%env(WEB3_SMART_CONTRACT_ADDRESS)%' - '%env(WEB3_HTTP_ENDPOINT)%' - App\Contract\TotalSupplyProviderInterface: '@total_supply_provider.env_var' \ No newline at end of file + App\Contract\TotalSupplyProviderInterface: '@total_supply_provider.web3' diff --git a/src/Command/BuildAssetsCommand.php b/src/Command/BuildAssetsCommand.php new file mode 100644 index 0000000..f4fa943 --- /dev/null +++ b/src/Command/BuildAssetsCommand.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Command; + +use App\Service\CollectionManager; +use RuntimeException; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Filesystem\Filesystem; + +/** + * @author Marco Lipparini + */ +#[AsCommand( + name: 'nft:build-assets', + description: 'Builds a new assets folder with all files shuffled using the current mapping', +)] +class BuildAssetsCommand extends Command +{ + /** + * @var string + */ + private const OUTPUT_PATH = 'output-path'; + + public function __construct( + private readonly CollectionManager $collectionManager, + private readonly Filesystem $filesystem, + string $name = null, + ) { + parent::__construct($name); + } + + protected function configure(): void + { + $this + ->addArgument( + self::OUTPUT_PATH, + InputArgument::REQUIRED, + 'The output path for the new files (local paths only)', + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $symfonyStyle = new SymfonyStyle($input, $output); + $outputPath = $input->getArgument(self::OUTPUT_PATH); + + if (! is_string($outputPath) || strlen($outputPath) <= 0) { + throw new RuntimeException('Invalid output path.'); + } + + if (is_dir($outputPath)) { + if (! $symfonyStyle->confirm( + "I'm about to delete the output directory and its content. Are you sure?", + false, + )) { + $symfonyStyle->warning('Aborting...'); + + return Command::SUCCESS; + } + + $this->filesystem->remove($outputPath); + $this->filesystem->mkdir($outputPath); + } + + $symfonyStyle->progressStart($this->collectionManager->getMaxTokenId()); + + foreach (range(1, $this->collectionManager->getMaxTokenId()) as $tokenId) { + $this->filesystem->copy( + $this->collectionManager->getAssetFileInfo($tokenId)->getPathname(), + $outputPath.'/'.$tokenId.'.'.$this->collectionManager->getAssetsExtension(), + ); + + $symfonyStyle->progressAdvance(); + } + + $symfonyStyle->progressFinish(); + + $symfonyStyle->success('Assets built successfully!'); + + return Command::SUCCESS; + } +} diff --git a/src/Command/BuildMetadataCommand.php b/src/Command/BuildMetadataCommand.php new file mode 100644 index 0000000..4578619 --- /dev/null +++ b/src/Command/BuildMetadataCommand.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Command; + +use App\Service\CollectionManager; +use Nette\Utils\Json; +use RuntimeException; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Filesystem\Filesystem; + +/** + * @author Marco Lipparini + */ +#[AsCommand( + name: 'nft:build-metadata', + description: 'Builds a new metadata folder with all files shuffled using the current mapping', +)] +class BuildMetadataCommand extends Command +{ + /** + * @var string + */ + private const URI_PREFIX = 'uri-prefix'; + + /** + * @var string + */ + private const OUTPUT_PATH = 'output-path'; + + public function __construct( + private readonly CollectionManager $collectionManager, + private readonly Filesystem $filesystem, + string $name = null, + ) { + parent::__construct($name); + } + + protected function configure(): void + { + $this + ->addArgument( + self::URI_PREFIX, + InputArgument::REQUIRED, + 'The URI prefix where the assets have been uploaded to', + ) + ; + + $this + ->addArgument( + self::OUTPUT_PATH, + InputArgument::REQUIRED, + 'The output path for the new files (local paths only)', + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $symfonyStyle = new SymfonyStyle($input, $output); + $uriPrefix = $input->getArgument(self::URI_PREFIX); + $outputPath = $input->getArgument(self::OUTPUT_PATH); + + if (! is_string($outputPath) || strlen($outputPath) <= 0) { + throw new RuntimeException('Invalid output path.'); + } + + if (! is_string($uriPrefix) || strlen($uriPrefix) <= 0) { + throw new RuntimeException('Invalid URI prefix.'); + } + + if (is_dir($outputPath)) { + if (! $symfonyStyle->confirm( + "I'm about to delete the output directory and its content. Are you sure?", + false, + )) { + $symfonyStyle->warning('Aborting...'); + + return Command::SUCCESS; + } + + $this->filesystem->remove($outputPath); + $this->filesystem->mkdir($outputPath); + } + + $symfonyStyle->progressStart($this->collectionManager->getMaxTokenId()); + + foreach (range(1, $this->collectionManager->getMaxTokenId()) as $tokenId) { + $this->filesystem->dumpFile( + $outputPath.'/'.$tokenId.'.json', + Json::encode( + $this->collectionManager->getMetadata($tokenId, trim($uriPrefix, '/').'/'.$tokenId.'.json'), + Json::PRETTY, + ), + ); + + $symfonyStyle->progressAdvance(); + } + + $symfonyStyle->progressFinish(); + + $symfonyStyle->success('Metadata built successfully!'); + + return Command::SUCCESS; + } +} diff --git a/src/Command/InitCollectionCommand.php b/src/Command/InitCollectionCommand.php deleted file mode 100644 index 8a16410..0000000 --- a/src/Command/InitCollectionCommand.php +++ /dev/null @@ -1,49 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace App\Command; - -use App\Service\CollectionManager; -use Symfony\Component\Console\Attribute\AsCommand; -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Style\SymfonyStyle; - -/** - * @author Marco Lipparini - */ -#[AsCommand( - name: 'nft:init-collection', - description: 'Creates the basic folder structure for the collection data', -)] -class InitCollectionCommand extends Command -{ - public function __construct( - private readonly CollectionManager $collectionManager, - string $name = null, - ) { - parent::__construct($name); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $symfonyStyle = new SymfonyStyle($input, $output); - - $this->collectionManager->createCollectionFolder(); - - $symfonyStyle->success('Metadata updated successfully!'); - - return Command::SUCCESS; - } -} diff --git a/src/Command/ShuffleCollectionCommand.php b/src/Command/ShuffleCollectionCommand.php index d4ee188..6a40f89 100644 --- a/src/Command/ShuffleCollectionCommand.php +++ b/src/Command/ShuffleCollectionCommand.php @@ -33,7 +33,12 @@ class ShuffleCollectionCommand extends Command /** * @var string */ - private const START_FROM_OPTION = 'start-from'; + private const MIN_TOKEN_ID = 'min'; + + /** + * @var string + */ + private const MAX_TOKEN_ID = 'max'; public function __construct( private readonly CollectionManager $collectionManager, @@ -44,20 +49,33 @@ public function __construct( protected function configure(): void { - $this - ->addOption(self::START_FROM_OPTION, 's', InputOption::VALUE_OPTIONAL, 'The first token ID to be shuffled') - ; + $this->addOption( + self::MIN_TOKEN_ID, + null, + InputOption::VALUE_OPTIONAL, + 'The minimum token ID to be shuffled', + ); + + $this->addOption( + self::MAX_TOKEN_ID, + null, + InputOption::VALUE_OPTIONAL, + 'The maximum token ID to be shuffled', + ); } protected function execute(InputInterface $input, OutputInterface $output): int { $symfonyStyle = new SymfonyStyle($input, $output); - $startFromTokenOptionValue = $input->getOption(self::START_FROM_OPTION) ?? 1; - $startTokenId = is_numeric($startFromTokenOptionValue) ? (int) $startFromTokenOptionValue : 1; - $maxTokenId = $this->collectionManager->getMaxTokenId(); + $minTokenIdOptionValue = $input->getOption(self::MIN_TOKEN_ID); + $minTokenId = is_numeric($minTokenIdOptionValue) ? (int) $minTokenIdOptionValue : 1; + $maxTokenIdOptionValue = $input->getOption(self::MAX_TOKEN_ID); + $maxTokenId = is_numeric( + $maxTokenIdOptionValue, + ) ? (int) $maxTokenIdOptionValue : $this->collectionManager->getMaxTokenId(); if (! $symfonyStyle->confirm( - 'You are about to shuffle your collection starting from token #'.$startTokenId.' up to token #'.$maxTokenId.'. Are you sure?', + 'You are about to shuffle your collection starting from token #'.$minTokenId.' up to token #'.$maxTokenId.'. This will overwrite the previous shuffle mapping. Are you sure?', false, )) { $symfonyStyle->warning('Aborting...'); @@ -65,26 +83,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int return Command::SUCCESS; } - $tokenIds = range($startTokenId, $maxTokenId); - shuffle($tokenIds); - - $symfonyStyle->progressStart(count($tokenIds)); - - foreach ($tokenIds as $i => $newId) { - $oldId = $i + $startTokenId; - - $this->collectionManager->temporarlyMoveToken($oldId, $newId); - - $symfonyStyle->progressAdvance(); - } - - $symfonyStyle->progressFinish(); - - $this->collectionManager->cleanTemporaryNames(); + $this->collectionManager->shuffle($minTokenId, $maxTokenId); $symfonyStyle->success('Collection shuffled successfully!'); - $symfonyStyle->info('Remember to run "bin/console nft:update-metadata URI_PREFIX" to update the json content!'); + $symfonyStyle->info('Remember to run "bin/console cache:clear" to invalidate metadata cache!'); return Command::SUCCESS; } diff --git a/src/Command/UpdateMetadataCommand.php b/src/Command/UpdateMetadataCommand.php deleted file mode 100644 index 23b984a..0000000 --- a/src/Command/UpdateMetadataCommand.php +++ /dev/null @@ -1,78 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace App\Command; - -use App\Service\CollectionManager; -use RuntimeException; -use Symfony\Component\Console\Attribute\AsCommand; -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Style\SymfonyStyle; - -/** - * @author Marco Lipparini - */ -#[AsCommand( - name: 'nft:update-metadata', - description: 'Updates the metadata inside all JSON files', -)] -class UpdateMetadataCommand extends Command -{ - /** - * @var string - */ - private const URI_PREFIX_OPTION = 'uri-prefix'; - - public function __construct( - private readonly CollectionManager $collectionManager, - string $name = null, - ) { - parent::__construct($name); - } - - protected function configure(): void - { - $this - ->addArgument( - self::URI_PREFIX_OPTION, - InputArgument::REQUIRED, - 'The URI prefix for assets (e.g. IPFS folder)', - ) - ; - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $symfonyStyle = new SymfonyStyle($input, $output); - $uriPrefix = $input->getArgument(self::URI_PREFIX_OPTION); - - if (! is_string($uriPrefix) || strlen($uriPrefix) <= 0) { - throw new RuntimeException('Invalid URI prefix.'); - } - - if (! $symfonyStyle->confirm('You are about to update your collection metadata. Are you sure?', false)) { - $symfonyStyle->warning('Aborting...'); - - return Command::SUCCESS; - } - - $this->collectionManager->updateMetadata($uriPrefix); - - $symfonyStyle->success('Metadata updated successfully!'); - - return Command::SUCCESS; - } -} diff --git a/src/Contract/AbstractNftController.php b/src/Contract/AbstractNftController.php index 056257e..d49d380 100644 --- a/src/Contract/AbstractNftController.php +++ b/src/Contract/AbstractNftController.php @@ -23,11 +23,6 @@ */ abstract class AbstractNftController extends AbstractController { - /** - * @var int - */ - protected const YEAR_CACHE_EXPIRATION = 60 * 60 * 24 * 356; - public function __construct( protected CollectionManager $collectionManager, protected TotalSupplyProviderInterface $totalSupplyProvider, @@ -36,11 +31,9 @@ public function __construct( ) { } - protected function isValidTokenId(string $tokenId): bool + protected function isValidTokenId(int $tokenId): bool { - $intTokenId = (int) $tokenId; - - return $intTokenId > 0 && $intTokenId <= $this->totalSupplyProvider->getTotalSupply(); + return $tokenId > 0 && $tokenId <= $this->totalSupplyProvider->getTotalSupply(); } protected function getDefaultCacheExpiration(): int diff --git a/src/Contract/CollectionContractInterface.php b/src/Contract/CollectionContractInterface.php new file mode 100644 index 0000000..57b38d5 --- /dev/null +++ b/src/Contract/CollectionContractInterface.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Contract; + +use Ethereum\DataType\EthQ; + +/** + * @author Marco Lipparini + */ +interface CollectionContractInterface +{ + public function totalSupply(): EthQ; +} diff --git a/src/Contract/CollectionFilesystemDriverInterface.php b/src/Contract/CollectionFilesystemDriverInterface.php new file mode 100644 index 0000000..9619ca8 --- /dev/null +++ b/src/Contract/CollectionFilesystemDriverInterface.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Contract; + +use SplFileInfo; + +/** + * @author Marco Lipparini + */ +interface CollectionFilesystemDriverInterface +{ + /** + * @var string + */ + final public const ASSETS_PATH = '/assets'; + + /** + * @var string + */ + final public const METADATA_PATH = '/metadata'; + + /** + * @var string + */ + final public const HIDDEN_METADATA_PATH = '/hidden/hidden.json'; + + /** + * @var string + */ + final public const HIDDEN_ASSET_PATH = '/hidden/hidden.'; + + /** + * @var string + */ + final public const ABI_PATH = '/abi.json'; + + /** + * @var string + */ + final public const MAPPING_PATH = '/mapping.json'; + + public function getAssetsExtension(): string; + + public function getHiddenAssetExtension(): string; + + /** + * @return array + */ + public function getMetadata(int $tokenId): array; + + public function getAssetFileInfo(int $tokenId): SplFileInfo; + + /** + * @return array + */ + public function getHiddenMetadata(): array; + + public function getHiddenAssetFileInfo(): SplFileInfo; + + /** + * @return object[] + */ + public function getAbi(): array; + + /** + * @return null|int[] + */ + public function getShuffleMapping(): ?array; + + /** + * @param int[] $newShuffleMapping + */ + public function storeNewShuffleMapping(array $newShuffleMapping): void; +} diff --git a/src/Contract/MetadataUpdaterInterface.php b/src/Contract/MetadataUpdaterInterface.php index c5f9464..00e0db9 100644 --- a/src/Contract/MetadataUpdaterInterface.php +++ b/src/Contract/MetadataUpdaterInterface.php @@ -13,8 +13,6 @@ namespace App\Contract; -use App\Service\CollectionManager; - /** * @author Marco Lipparini */ @@ -23,10 +21,5 @@ interface MetadataUpdaterInterface /** * @param array $metadata */ - public function updateMetadata( - array &$metadata, - string $uriPrefix, - string $tokenId, - CollectionManager $collectionManager, - ): void; + public function updateMetadata(array &$metadata, int $tokenId, string $assetUri): void; } diff --git a/src/Controller/AssetController.php b/src/Controller/AssetController.php index 0563fa6..8278a07 100644 --- a/src/Controller/AssetController.php +++ b/src/Controller/AssetController.php @@ -22,22 +22,29 @@ /** * @author Marco Lipparini */ -#[Route('/asset/{tokenId}.{_format}', name: RouteName::GET_ASSET)] +#[Route( + '/asset/{tokenId}.{_format}', + name: RouteName::GET_ASSET, + defaults: [ + '_format' => null, + ], +)] final class AssetController extends AbstractNftController { - public function __invoke(string $tokenId): Response + public function __invoke(int $tokenId): Response { if (! $this->isValidTokenId($tokenId)) { throw $this->createNotFoundException(); } - return $this->file( - $this->collectionManager->getAssetPath($tokenId), - null, - ResponseHeaderBag::DISPOSITION_INLINE, - ) + return $this + ->file( + $this->collectionManager->getAssetFileInfo($tokenId), + null, + ResponseHeaderBag::DISPOSITION_INLINE, + ) ->setPublic() - ->setMaxAge(self::YEAR_CACHE_EXPIRATION) + ->setMaxAge($this->getDefaultCacheExpiration()) ; } } diff --git a/src/Controller/HiddenAssetController.php b/src/Controller/HiddenAssetController.php index da2eb46..0d13844 100644 --- a/src/Controller/HiddenAssetController.php +++ b/src/Controller/HiddenAssetController.php @@ -15,7 +15,6 @@ use App\Config\RouteName; use App\Contract\AbstractNftController; -use App\Service\CollectionManager; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\Routing\Annotation\Route; @@ -23,14 +22,21 @@ /** * @author Marco Lipparini */ -#[Route('/hidden', name: RouteName::GET_HIDDEN_ASSET)] +#[Route( + '/hidden.{_format}', + name: RouteName::GET_HIDDEN_ASSET, + defaults: [ + '_format' => null, + ], +)] final class HiddenAssetController extends AbstractNftController { - public function __invoke(CollectionManager $collectionManager): Response + public function __invoke(): Response { - return $this->file($collectionManager->getHiddenFilePath(), null, ResponseHeaderBag::DISPOSITION_INLINE) + return $this + ->file($this->collectionManager->getHiddenAssetFileInfo(), null, ResponseHeaderBag::DISPOSITION_INLINE) ->setPublic() - ->setMaxAge(self::YEAR_CACHE_EXPIRATION) + ->setMaxAge($this->getDefaultCacheExpiration()) ; } } diff --git a/src/Controller/MetadataController.php b/src/Controller/MetadataController.php index c28388b..34ae8b4 100644 --- a/src/Controller/MetadataController.php +++ b/src/Controller/MetadataController.php @@ -15,12 +15,9 @@ use App\Config\RouteName; use App\Contract\AbstractNftController; -use Nette\Utils\FileSystem; -use Nette\Utils\Json; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Contracts\Cache\ItemInterface; /** * @author Marco Lipparini @@ -31,40 +28,51 @@ requirements: [ '_format' => 'json', ], + defaults: [ + '_format' => 'json', + ], )] final class MetadataController extends AbstractNftController { - public function __invoke(string $tokenId): Response + /** + * @var string + */ + private const CACHE_TOKEN_METADATA = 'metadata_controller.metadata_'; + + /** + * @var string + */ + private const CACHE_HIDDEN_METADATA = 'collection_manager.hidden_metadata'; + + public function __invoke(int $tokenId): Response { if (! $this->isValidTokenId($tokenId)) { - $hiddenMetadata = $this->cache->get('metadata_controller.hidden_metadata', function (): array { - /** @var array $hiddenMetadata */ - $hiddenMetadata = Json::decode( - FileSystem::read($this->collectionManager->getHiddenMetadataPath()), - Json::FORCE_ARRAY, - ); - $hiddenMetadata['image'] = $this->urlGenerator->generate( - 'hidden_asset', - [], - UrlGeneratorInterface::ABSOLUTE_URL, - ); + $metadata = $this->cache->get(self::CACHE_HIDDEN_METADATA, function (ItemInterface $item): array { + $item->expiresAfter($this->getDefaultCacheExpiration()); - return $hiddenMetadata; + return $this->collectionManager->getHiddenMetadata(); }); - return $this->json($hiddenMetadata) + return $this + ->json($metadata) ->setPublic() ->setMaxAge($this->getDefaultCacheExpiration()) ; } - return $this->file( - $this->collectionManager->getMetadataPath($tokenId), - null, - ResponseHeaderBag::DISPOSITION_INLINE, - ) + $metadata = $this->cache->get( + self::CACHE_TOKEN_METADATA.$tokenId, + function (ItemInterface $item) use ($tokenId): array { + $item->expiresAfter($this->getDefaultCacheExpiration()); + + return $this->collectionManager->getMetadata($tokenId); + }, + ); + + return $this + ->json($metadata) ->setPublic() - ->setMaxAge(self::YEAR_CACHE_EXPIRATION) + ->setMaxAge($this->getDefaultCacheExpiration()) ; } } diff --git a/src/Controller/TotalSupplyController.php b/src/Controller/TotalSupplyController.php index a380c87..1c43d59 100644 --- a/src/Controller/TotalSupplyController.php +++ b/src/Controller/TotalSupplyController.php @@ -17,6 +17,7 @@ use App\Contract\AbstractNftController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Contracts\Cache\ItemInterface; /** * @author Marco Lipparini @@ -24,10 +25,22 @@ #[Route('/total-supply', name: RouteName::GET_TOTAL_SUPPLY)] final class TotalSupplyController extends AbstractNftController { + /** + * @var string + */ + private const CACHE_RESPONSE_DATA = 'total_supply_controller.response_data'; + public function __invoke(): Response { - return $this->json([ - 'total_supply' => $this->totalSupplyProvider->getTotalSupply(), - ]); + /** @var array $responseData */ + $responseData = $this->cache->get(self::CACHE_RESPONSE_DATA, function (ItemInterface $item): array { + $item->expiresAfter($this->getDefaultCacheExpiration()); + + return [ + 'total_supply' => $this->totalSupplyProvider->getTotalSupply(), + ]; + }); + + return $this->json($responseData); } } diff --git a/src/Exception/InvalidTokenIdException.php b/src/Exception/InvalidTokenIdException.php new file mode 100644 index 0000000..07fb5d6 --- /dev/null +++ b/src/Exception/InvalidTokenIdException.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Exception; + +use RuntimeException; + +/** + * @author Marco Lipparini + */ +final class InvalidTokenIdException extends RuntimeException +{ + public function __construct(int $tokenId) + { + parent::__construct('Invalid token ID: '.$tokenId); + } +} diff --git a/src/Exception/InvalidTokensRangeException.php b/src/Exception/InvalidTokensRangeException.php new file mode 100644 index 0000000..e49872e --- /dev/null +++ b/src/Exception/InvalidTokensRangeException.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\Exception; + +use RuntimeException; + +/** + * @author Marco Lipparini + */ +final class InvalidTokensRangeException extends RuntimeException +{ + public function __construct(int $min, int $max) + { + parent::__construct('Invalid tokens range: '.$min.'-'.$max); + } +} diff --git a/src/FilesystemDriver/LocalFilesystemDriver.php b/src/FilesystemDriver/LocalFilesystemDriver.php new file mode 100644 index 0000000..d49a6df --- /dev/null +++ b/src/FilesystemDriver/LocalFilesystemDriver.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\FilesystemDriver; + +use App\Contract\CollectionFilesystemDriverInterface; +use LogicException; +use Nette\Utils\FileSystem; +use Nette\Utils\Json; +use SplFileInfo; +use Symfony\Component\HttpFoundation\File\File; + +/** + * @author Marco Lipparini + */ +final class LocalFilesystemDriver implements CollectionFilesystemDriverInterface +{ + /** + * @var int[] + */ + private array $shuffleMapping = []; + + public function __construct( + private readonly string $localCollectionPath, + private readonly string $assetsExtension, + private readonly string $hiddenAssetExtension, + ) { + } + + public function getAssetsExtension(): string + { + return $this->assetsExtension; + } + + public function getHiddenAssetExtension(): string + { + return $this->hiddenAssetExtension; + } + + /** + * @inheritdoc + */ + public function getMetadata(int $tokenId): array + { + $metadataPath = $this->localCollectionPath.self::METADATA_PATH.'/'.$tokenId.'.json'; + $metadata = Json::decode(FileSystem::read($metadataPath), Json::FORCE_ARRAY); + + if (! is_array($metadata)) { + throw new LogicException('Unexpected metadata value (it must be an array).'); + } + + /** @var array $metadata */ + + return $metadata; + } + + public function getAssetFileInfo(int $tokenId): SplFileInfo + { + return new File($this->localCollectionPath.self::ASSETS_PATH.'/'.$tokenId.'.'.$this->assetsExtension); + } + + /** + * @inheritdoc + */ + public function getHiddenMetadata(): array + { + $hiddenMetadataPath = $this->localCollectionPath.self::HIDDEN_METADATA_PATH; + $metadata = Json::decode(FileSystem::read($hiddenMetadataPath), Json::FORCE_ARRAY); + + if (! is_array($metadata)) { + throw new LogicException('Unexpected metadata value (it must be an array).'); + } + + /** @var array $metadata */ + + return $metadata; + } + + public function getHiddenAssetFileInfo(): SplFileInfo + { + return new File($this->localCollectionPath.self::HIDDEN_ASSET_PATH.$this->hiddenAssetExtension); + } + + /** + * @return object[] + */ + public function getAbi(): array + { + $abi = Json::decode(FileSystem::read($this->localCollectionPath.self::ABI_PATH)); + + if (! is_array($abi)) { + throw new LogicException('Unexpected ABI value (it must be an array).'); + } + + /** @var object[] $abi */ + + return $abi; + } + + public function getShuffleMapping(): ?array + { + if (empty($this->shuffleMapping)) { + $mappingPath = $this->localCollectionPath.self::MAPPING_PATH; + + if (! is_file($mappingPath)) { + return null; + } + + /** @var int[] $shuffleMappingData */ + $shuffleMappingData = Json::decode(FileSystem::read($mappingPath), Json::FORCE_ARRAY); + + $this->shuffleMapping = $shuffleMappingData; + } + + return $this->shuffleMapping; + } + + public function storeNewShuffleMapping(array $newShuffleMapping): void + { + FileSystem::write($this->localCollectionPath.self::MAPPING_PATH, Json::encode($newShuffleMapping)); + } +} diff --git a/src/FilesystemDriver/S3FilesystemDriver.php b/src/FilesystemDriver/S3FilesystemDriver.php new file mode 100644 index 0000000..b0cefb3 --- /dev/null +++ b/src/FilesystemDriver/S3FilesystemDriver.php @@ -0,0 +1,161 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace App\FilesystemDriver; + +use App\Contract\CollectionFilesystemDriverInterface; +use Aws\S3\S3Client; +use LogicException; +use Nette\Utils\FileSystem; +use Nette\Utils\Json; +use SplFileInfo; +use Symfony\Component\HttpFoundation\File\File; + +/** + * @author Marco Lipparini + */ +final class S3FilesystemDriver implements CollectionFilesystemDriverInterface +{ + private readonly S3Client $s3Client; + + /** + * @var int[] + */ + private array $shuffleMapping = []; + + public function __construct( + readonly string $region, + readonly string $endpointUrl, + readonly string $accessKey, + readonly string $secretKey, + private readonly string $bucketName, + private readonly string $objectsKeyPrefix, + private readonly string $assetsExtension, + private readonly string $hiddenAssetExtension, + ) { + $this->s3Client = new S3Client([ + 'version' => 'latest', + 'region' => $region, + 'endpoint' => $endpointUrl, + 'credentials' => [ + 'key' => $accessKey, + 'secret' => $secretKey, + ], + 'http' => [ + 'connect_timeout' => 5, + 'timeout' => 10, + ], + ]); + + $this->s3Client->registerStreamWrapper(); + } + + public function getAssetsExtension(): string + { + return $this->assetsExtension; + } + + public function getHiddenAssetExtension(): string + { + return $this->hiddenAssetExtension; + } + + /** + * @inheritdoc + */ + public function getMetadata(int $tokenId): array + { + $metadataPath = $this->buildS3Path(self::METADATA_PATH.'/'.$tokenId.'.json'); + $metadata = Json::decode(FileSystem::read($metadataPath), Json::FORCE_ARRAY); + + if (! is_array($metadata)) { + throw new LogicException('Unexpected metadata value (it must be an array).'); + } + + /** @var array $metadata */ + + return $metadata; + } + + public function getAssetFileInfo(int $tokenId): SplFileInfo + { + return new File($this->buildS3Path(self::ASSETS_PATH.'/'.$tokenId.'.'.$this->assetsExtension)); + } + + /** + * @inheritdoc + */ + public function getHiddenMetadata(): array + { + $metadata = Json::decode(FileSystem::read($this->buildS3Path(self::HIDDEN_METADATA_PATH)), Json::FORCE_ARRAY); + + if (! is_array($metadata)) { + throw new LogicException('Unexpected metadata value (it must be an array).'); + } + + /** @var array $metadata */ + + return $metadata; + } + + public function getHiddenAssetFileInfo(): SplFileInfo + { + return new File($this->buildS3Path(self::HIDDEN_ASSET_PATH.$this->hiddenAssetExtension)); + } + + /** + * @return object[] + */ + public function getAbi(): array + { + $abi = Json::decode(FileSystem::read($this->buildS3Path(self::ABI_PATH))); + + if (! is_array($abi)) { + throw new LogicException('Unexpected ABI value (it must be an array).'); + } + + /** @var object[] $abi */ + + return $abi; + } + + public function getShuffleMapping(): ?array + { + if (empty($this->shuffleMapping)) { + $mappingPath = $this->buildS3Path(self::MAPPING_PATH); + + if (! is_file($mappingPath)) { + return null; + } + + /** @var int[] $shuffleMappingData */ + $shuffleMappingData = Json::decode(FileSystem::read($mappingPath), Json::FORCE_ARRAY); + + $this->shuffleMapping = $shuffleMappingData; + } + + return $this->shuffleMapping; + } + + public function storeNewShuffleMapping(array $newShuffleMapping): void + { + FileSystem::write($this->buildS3Path(self::MAPPING_PATH), Json::encode($newShuffleMapping), null); + } + + private function buildS3Path(string $relativePath): string + { + $keyPrefix = empty($this->objectsKeyPrefix) ? '' : trim($this->objectsKeyPrefix, '/').'/'; + + return 's3://'.$this->bucketName.'/'.$keyPrefix.trim($relativePath, '/'); + } +} diff --git a/src/MetadataUpdater/SabcMetadataUpdater.php b/src/MetadataUpdater/SabcMetadataUpdater.php index 29e8c1c..1d80a73 100644 --- a/src/MetadataUpdater/SabcMetadataUpdater.php +++ b/src/MetadataUpdater/SabcMetadataUpdater.php @@ -14,7 +14,6 @@ namespace App\MetadataUpdater; use App\Contract\MetadataUpdaterInterface; -use App\Service\CollectionManager; /** * This is an example custom metadata updater for the SABC collection. @@ -27,13 +26,9 @@ */ final class SabcMetadataUpdater implements MetadataUpdaterInterface { - public function updateMetadata( - array &$metadata, - string $uriPrefix, - string $tokenId, - CollectionManager $collectionManager, - ): void { + public function updateMetadata(array &$metadata, int $tokenId, string $assetUri): void + { $metadata['name'] = 'SABC #'.$tokenId; - $metadata['edition'] = (int) $tokenId; + $metadata['edition'] = $tokenId; } } diff --git a/src/MetadataUpdater/UriUpdater.php b/src/MetadataUpdater/UriUpdater.php index f50bee9..db6af55 100644 --- a/src/MetadataUpdater/UriUpdater.php +++ b/src/MetadataUpdater/UriUpdater.php @@ -14,19 +14,14 @@ namespace App\MetadataUpdater; use App\Contract\MetadataUpdaterInterface; -use App\Service\CollectionManager; /** * @author Marco Lipparini */ final class UriUpdater implements MetadataUpdaterInterface { - public function updateMetadata( - array &$metadata, - string $uriPrefix, - string $tokenId, - CollectionManager $collectionManager, - ): void { - $metadata['image'] = $uriPrefix.'/'.$tokenId.'.'.$collectionManager->getAssetsExtension(); + public function updateMetadata(array &$metadata, int $tokenId, string $assetUri): void + { + $metadata['image'] = $assetUri; } } diff --git a/src/Service/CollectionManager.php b/src/Service/CollectionManager.php index ed596ba..60b80a7 100644 --- a/src/Service/CollectionManager.php +++ b/src/Service/CollectionManager.php @@ -13,13 +13,13 @@ namespace App\Service; +use App\Config\RouteName; +use App\Contract\CollectionFilesystemDriverInterface; use App\Contract\MetadataUpdaterInterface; -use LogicException; -use Nette\Utils\FileSystem as NetteFilesystem; -use Nette\Utils\Json; -use RuntimeException; -use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\Finder\Finder; +use App\Exception\InvalidTokenIdException; +use App\Exception\InvalidTokensRangeException; +use SplFileInfo; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Contracts\Cache\CacheInterface; /** @@ -30,218 +30,131 @@ final class CollectionManager /** * @var string */ - private const COLLECTION_PATH = __DIR__.'/../../collection'; - - /** - * @var string - */ - private const ASSETS_PATH = self::COLLECTION_PATH.'/assets'; - - /** - * @var string - */ - private const METADATA_PATH = self::COLLECTION_PATH.'/metadata'; - - /** - * @var string - */ - private const HIDDEN_PATH = self::COLLECTION_PATH.'/hidden'; - - private int $maxTokenId; - - private string $assetsExtension; + private const CACHE_MAPPING = 'collection_manager.mapping'; /** * @param iterable $metadataUpdaters */ public function __construct( + private readonly int $maxTokenId, private readonly iterable $metadataUpdaters, - private readonly Filesystem $filesystem, + private readonly CollectionFilesystemDriverInterface $collectionFilesystemDriver, private readonly CacheInterface $cache, + private readonly UrlGeneratorInterface $urlGenerator, ) { } - public function createCollectionFolder(): void - { - if ($this->filesystem->exists(self::COLLECTION_PATH)) { - throw new RuntimeException('The collection folder already exists in "'.realpath( - self::COLLECTION_PATH, - ).'".'); - } - - $this->filesystem->mkdir(self::COLLECTION_PATH); - $this->filesystem->mkdir(self::ASSETS_PATH); - $this->filesystem->mkdir(self::METADATA_PATH); - $this->filesystem->mkdir(self::HIDDEN_PATH); - } - public function getMaxTokenId(): int { - if (! isset($this->maxTokenId)) { - /** @var int $cachedMaxTokenId */ - $cachedMaxTokenId = $this->cache->get('collection_manager.max_token_id', function (): int { - $maxTokenId = 1; - $metadataFinder = (new Finder())->files()->in(self::METADATA_PATH)->name('*.json'); - - foreach ($metadataFinder->getIterator() as $metadataFile) { - $id = (int) $metadataFile->getFilenameWithoutExtension(); - - if ($id > $maxTokenId) { - $maxTokenId = $id; - } - } - - return $maxTokenId; - }); - - $this->maxTokenId = $cachedMaxTokenId; - } - return $this->maxTokenId; } - public function temporarlyMoveToken(int $oldId, int $newId): void - { - $this->filesystem->rename($this->getMetadataPath($oldId), $this->getMetadataPath('_'.$newId)); - $this->filesystem->rename($this->getAssetPath($oldId), $this->getAssetPath('_'.$newId)); - } - - public function cleanTemporaryNames(): void + public function shuffle(int $min, int $max): void { - // Metadata - $metadataFinder = (new Finder())->files()->in(self::METADATA_PATH)->name('_*.json'); - - foreach ($metadataFinder->getIterator() as $metadataFile) { - $oldFile = $metadataFile->getRealPath(); - $newFile = $metadataFile->getPath().'/'.substr($metadataFile->getFilename(), 1); - - if (! is_string($oldFile)) { - throw new RuntimeException('Invalid old file path.'); - } - - $this->filesystem->rename($oldFile, $newFile); + if ($min <= 0 || $min >= $max || $max > $this->maxTokenId) { + throw new InvalidTokensRangeException($min, $max); } - // Assets - $assetsFinder = (new Finder())->files()->in(self::ASSETS_PATH)->name('_*.'.$this->getAssetsExtension()); + $tokenIds = range(1, $this->maxTokenId); - foreach ($assetsFinder->getIterator() as $assetFile) { - $oldFile = $assetFile->getRealPath(); - $newFile = $assetFile->getPath().'/'.substr($assetFile->getFilename(), 1); + $beforeRange = array_slice($tokenIds, 0, $min - 1); + $range = array_slice($tokenIds, $min - 1, $max - ($min - 1)); + $afterRange = array_slice($tokenIds, $max); + shuffle($range); - if (! is_string($oldFile)) { - throw new RuntimeException('Invalid old file path.'); - } + $this->collectionFilesystemDriver->storeNewShuffleMapping(array_merge($beforeRange, $range, $afterRange)); - $this->filesystem->rename($oldFile, $newFile); - } + $this->cache->delete(self::CACHE_MAPPING); } - public function updateUris(?string $uriPrefix): void + public function getAssetsExtension(): string { - $metadataFinder = (new Finder())->files()->in(self::METADATA_PATH)->name('*.json'); - - foreach ($metadataFinder->getIterator() as $metadataFile) { - $jsonFilePath = $metadataFile->getRealPath(); - $tokenId = $metadataFile->getFilenameWithoutExtension(); - - if (! is_string($jsonFilePath)) { - throw new RuntimeException('Invalid JSON file path.'); - } - - /** @var array $jsonContent */ - $jsonContent = Json::decode(NetteFilesystem::read($jsonFilePath), Json::FORCE_ARRAY); - - $jsonContent['image'] = $uriPrefix.'/'.$tokenId.'.'.$this->getAssetsExtension(); - - NetteFilesystem::write($jsonFilePath, Json::encode($jsonContent, Json::PRETTY)); - } + return $this->collectionFilesystemDriver->getAssetsExtension(); } - public function updateMetadata(string $uriPrefix): void + public function getHiddenAssetExtension(): string { - $metadataFinder = (new Finder())->files()->in(self::METADATA_PATH)->name('*.json'); - - foreach ($metadataFinder->getIterator() as $metadataFile) { - $jsonFilePath = $metadataFile->getRealPath(); - $tokenId = $metadataFile->getFilenameWithoutExtension(); - - if (! is_string($jsonFilePath)) { - throw new RuntimeException('Invalid JSON file path.'); - } - - $jsonContent = Json::decode(NetteFilesystem::read($jsonFilePath), Json::FORCE_ARRAY); - - foreach ($this->metadataUpdaters as $metadataUpdater) { - $metadataUpdater->updateMetadata($jsonContent, $uriPrefix, $tokenId, $this); - } - - NetteFilesystem::write($jsonFilePath, Json::encode($jsonContent, Json::PRETTY)); - } + return $this->collectionFilesystemDriver->getHiddenAssetExtension(); } - public function getMetadataPath(int|string $tokenId): string + /** + * @return array + */ + public function getMetadata(int $tokenId, string $assetUri = null): array { - return self::METADATA_PATH.'/'.$tokenId.'.json'; + $metadata = $this->collectionFilesystemDriver->getMetadata($this->getMappedTokenId($tokenId)); + + foreach ($this->metadataUpdaters as $metadataUpdater) { + $metadataUpdater->updateMetadata( + $metadata, + $tokenId, + $assetUri ?? $this->urlGenerator->generate( + RouteName::GET_ASSET, + [ + 'tokenId' => $tokenId, + ], + UrlGeneratorInterface::ABSOLUTE_URL, + ), + ); + } + + return $metadata; } - public function getAssetPath(int|string $tokenId): string + public function getAssetFileInfo(int $tokenId): SplFileInfo { - return self::ASSETS_PATH.'/'.$tokenId.'.'.$this->getAssetsExtension(); + return $this->collectionFilesystemDriver->getAssetFileInfo($this->getMappedTokenId($tokenId)); } - public function getHiddenFilePath(): string + /** + * @return array + */ + public function getHiddenMetadata(string $assetUri = null): array { - $cachedHiddenFilePath = $this->cache->get('collection_manager.hidden_file_path', function (): string { - $hiddenMetadataFinder = (new Finder())->files()->in(__DIR__.'/../../collection/hidden')->notName('*.json'); - - foreach ($hiddenMetadataFinder->getIterator() as $hiddenMetadataFile) { - $hiddenMetadataFilePath = $hiddenMetadataFile->getRealPath(); + $hiddenMetadata = $this->collectionFilesystemDriver->getHiddenMetadata(); - if (! is_string($hiddenMetadataFilePath)) { - throw new RuntimeException('Invalid JSON file path (hidden metadata).'); - } - - return $hiddenMetadataFilePath; - } - - throw new RuntimeException('Unable to detect "hidden" file.'); - }); - - if (! is_string($cachedHiddenFilePath)) { - throw new LogicException('Unexpected value type (this should never happen).'); - } + $hiddenMetadata['image'] = $assetUri ?? $this->urlGenerator->generate( + RouteName::GET_HIDDEN_ASSET, + [], + UrlGeneratorInterface::ABSOLUTE_URL, + ); - return $cachedHiddenFilePath; + return $hiddenMetadata; } - public function getHiddenMetadataPath(): string + public function getHiddenAssetFileInfo(): SplFileInfo { - return self::COLLECTION_PATH.'/hidden/hidden.json'; + return $this->collectionFilesystemDriver->getHiddenAssetFileInfo(); } - public function getAbi(): string + /** + * @return object[] + */ + public function getAbi(): array { - return NetteFilesystem::read(self::COLLECTION_PATH.'/abi.json'); + return $this->collectionFilesystemDriver->getAbi(); } - public function getAssetsExtension(): string + /** + * @return null|int[] + */ + public function getShuffleMapping(): ?array { - if (! isset($this->assetsExtension)) { - /** @var string $cachedAssetsExtension */ - $cachedAssetsExtension = $this->cache->get('collection_manager.assets_extension', function (): string { - $assetsFinder = (new Finder())->files()->in(self::ASSETS_PATH); + return $this->collectionFilesystemDriver->getShuffleMapping(); + } - foreach ($assetsFinder->getIterator() as $hiddenMetadataFile) { - return $hiddenMetadataFile->getExtension(); - } + private function getMappedTokenId(int $tokenId): int + { + $shuffleMapping = $this->collectionFilesystemDriver->getShuffleMapping(); - throw new RuntimeException('Unable to detect assets extension.'); - }); + if (null === $shuffleMapping) { + return $tokenId; + } - $this->assetsExtension = $cachedAssetsExtension; + if (! isset($shuffleMapping[$tokenId - 1])) { + throw new InvalidTokenIdException($tokenId); } - return $this->assetsExtension; + return $shuffleMapping[$tokenId - 1]; } } diff --git a/src/TotalSupplyProvider/OpenSeaStatsProvider.php b/src/TotalSupplyProvider/OpenSeaStatsProvider.php index 8eb30d8..7325d6d 100644 --- a/src/TotalSupplyProvider/OpenSeaStatsProvider.php +++ b/src/TotalSupplyProvider/OpenSeaStatsProvider.php @@ -14,9 +14,6 @@ namespace App\TotalSupplyProvider; use App\Contract\TotalSupplyProviderInterface; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; -use Symfony\Contracts\Cache\CacheInterface; -use Symfony\Contracts\Cache\ItemInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; /** @@ -29,31 +26,19 @@ final class OpenSeaStatsProvider implements TotalSupplyProviderInterface public function __construct( private readonly string $collectionSlug, private readonly HttpClientInterface $httpClient, - private readonly CacheInterface $cache, - private readonly ParameterBagInterface $parameterBag, ) { } public function getTotalSupply(): int { if (! isset($this->totalSupply)) { - /** @var int $cachedTotalSupply */ - $cachedTotalSupply = $this->cache->get( - 'open_sea_provider.total_supply', - function (ItemInterface $item): int { - $item->expiresAfter((int) $this->parameterBag->get('app.cache_expiration')); - - $response = $this->httpClient->request( - 'GET', - 'https://api.opensea.io/api/v1/collection/'.$this->collectionSlug, - ); - $jsonContent = $response->toArray(); - - return (int) $jsonContent['collection']['stats']['total_supply']; - }, + $response = $this->httpClient->request( + 'GET', + 'https://api.opensea.io/api/v1/collection/'.$this->collectionSlug, ); + $jsonContent = $response->toArray(); - $this->totalSupply = $cachedTotalSupply; + $this->totalSupply = (int) $jsonContent['collection']['stats']['total_supply']; } return $this->totalSupply; diff --git a/src/TotalSupplyProvider/Web3Provider.php b/src/TotalSupplyProvider/Web3Provider.php index ec7dbc9..254270b 100644 --- a/src/TotalSupplyProvider/Web3Provider.php +++ b/src/TotalSupplyProvider/Web3Provider.php @@ -13,14 +13,12 @@ namespace App\TotalSupplyProvider; +use App\Contract\CollectionContractInterface; use App\Contract\TotalSupplyProviderInterface; use App\Service\CollectionManager; -use phpseclib\Math\BigInteger; +use Ethereum\Ethereum; +use Ethereum\SmartContract; use RuntimeException; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; -use Symfony\Contracts\Cache\CacheInterface; -use Symfony\Contracts\Cache\ItemInterface; -use Web3\Contract; /** * @author Marco Lipparini @@ -29,45 +27,32 @@ final class Web3Provider implements TotalSupplyProviderInterface { private int $totalSupply; - private readonly Contract $contract; + private readonly SmartContract $contract; public function __construct( - private readonly string $contractAddress, + string $contractAddress, string $infuraEndpoint, CollectionManager $collectionManager, - private readonly CacheInterface $cache, - private readonly ParameterBagInterface $parameterBag, ) { - $this->contract = new Contract($infuraEndpoint, $collectionManager->getAbi()); + $this->contract = new SmartContract( + $collectionManager->getAbi(), + $contractAddress, + new Ethereum($infuraEndpoint), + ); } public function getTotalSupply(): int { if (! isset($this->totalSupply)) { - /** @var int $cachedTotalSupply */ - $cachedTotalSupply = $this->cache->get('web3_provider.total_supply', function (ItemInterface $item): int { - $item->expiresAfter((int) $this->parameterBag->get('app.cache_expiration')); - $totalSupply = 0; + /** @var CollectionContractInterface $smartContract */ + $smartContract = $this->contract; + $totalSupply = $smartContract->totalSupply()->val(); - $this->contract->at($this->contractAddress)->call( - 'totalSupply', - [], - function ($error, $decodedTransaction) use (&$totalSupply): void { - /** @var BigInteger $result */ - $result = $decodedTransaction[0]; + if (! is_int($totalSupply)) { + throw new RuntimeException('Unexpected result from "totalSupply" call: "'.$totalSupply.'"'); + } - $totalSupply = (int) $result->toString(); - }, - ); - - if (0 === $totalSupply) { - throw new RuntimeException('Unable to get total supply using Web3 provider.'); - } - - return $totalSupply; - }); - - $this->totalSupply = $cachedTotalSupply; + $this->totalSupply = $totalSupply; } return $this->totalSupply; diff --git a/symfony.lock b/symfony.lock index 739a312..d5db655 100644 --- a/symfony.lock +++ b/symfony.lock @@ -1,7 +1,19 @@ { + "aws/aws-crt-php": { + "version": "v1.0.2" + }, + "aws/aws-sdk-php": { + "version": "3.209.2" + }, "composer/package-versions-deprecated": { "version": "1.11.99.4" }, + "digitaldonkey/ecverify": { + "version": "1.0" + }, + "digitaldonkey/ethereum-php": { + "version": "dev-master" + }, "doctrine/annotations": { "version": "1.13", "recipe": { @@ -88,6 +100,9 @@ "friendsofphp/proxy-manager-lts": { "version": "v1.0.5" }, + "graze/guzzle-jsonrpc": { + "version": "3.2.1" + }, "guzzlehttp/guzzle": { "version": "6.5.5" }, @@ -106,6 +121,9 @@ "monolog/monolog": { "version": "2.3.5" }, + "mtdowling/jmespath.php": { + "version": "2.6.1" + }, "myclabs/deep-copy": { "version": "1.10.2" }, @@ -118,6 +136,9 @@ "nikic/php-parser": { "version": "v4.13.2" }, + "pear/math_biginteger": { + "version": "v1.0.3" + }, "phar-io/manifest": { "version": "2.0.3" }, @@ -133,9 +154,6 @@ "phpdocumentor/type-resolver": { "version": "1.5.1" }, - "phpseclib/phpseclib": { - "version": "2.0.35" - }, "phpspec/prophecy": { "version": "v1.15.0" }, @@ -201,9 +219,6 @@ "rector/rector": { "version": "0.12.10" }, - "sc0vu/web3.php": { - "version": "dev-master" - }, "sebastian/cli-parser": { "version": "1.0.1" }, @@ -264,6 +279,15 @@ "config/packages/sensio_framework_extra.yaml" ] }, + "simplito/bigint-wrapper-php": { + "version": "1.0.0" + }, + "simplito/bn-php": { + "version": "1.1.2" + }, + "simplito/elliptic-php": { + "version": "1.0.9" + }, "symfony/apache-pack": { "version": "1.0", "recipe": {