From 380377b27c3794dbfd37702e823dd020253377b6 Mon Sep 17 00:00:00 2001 From: ghost Date: Mon, 2 Oct 2023 16:13:55 +0300 Subject: [PATCH] init symfony framework #14 --- .env | 50 + .env.test | 6 + .gitignore | 42 +- bin/console | 17 + bin/phpunit | 19 + composer.json | 108 +- composer.lock | 9748 +++++++++++++++++ config/bundles.php | 14 + config/packages/cache.yaml | 19 + config/packages/debug.yaml | 5 + config/packages/doctrine.yaml | 48 + config/packages/doctrine_migrations.yaml | 6 + config/packages/framework.yaml | 25 + config/packages/mailer.yaml | 3 + config/packages/messenger.yaml | 24 + config/packages/monolog.yaml | 61 + config/packages/notifier.yaml | 13 + config/packages/routing.yaml | 12 + config/packages/security.yaml | 39 + config/packages/translation.yaml | 15 + config/packages/twig.yaml | 9 + config/packages/validator.yaml | 13 + config/packages/web_profiler.yaml | 17 + config/preload.php | 5 + config/routes.yaml | 5 + config/routes/framework.yaml | 4 + config/routes/web_profiler.yaml | 8 + config/services.yaml | 26 + database/yggtracker.mwb | Bin 44565 -> 0 bytes docker-compose.override.yml | 14 + docker-compose.yml | 21 + example/environment/crontab | 10 - example/environment/nginx | 29 - example/environment/sphinx.conf | 71 - .../log/index.html => migrations/.gitignore | 0 phpunit.xml.dist | 38 + .../asset}/default/css/common.css | 0 .../asset}/default/css/framework.css | 74 +- public/index.php | 9 + src/Controller/.gitignore | 0 src/Controller/HomeController.php | 20 + src/Controller/PageController.php | 67 + src/Controller/ProfileController.php | 76 + src/Controller/SearchController.php | 31 + src/Entity/.gitignore | 0 src/Entity/Page.php | 27 + src/Entity/User.php | 147 + src/Kernel.php | 11 + src/Repository/.gitignore | 0 src/Repository/PageRepository.php | 48 + src/Repository/UserRepository.php | 48 + src/Service/User.php | 12 + src/app/controller/index.php | 151 - src/app/controller/module/footer.php | 13 - src/app/controller/module/head.php | 54 - src/app/controller/module/header.php | 19 - src/app/controller/module/page.php | 9 - src/app/controller/module/pagination.php | 43 - src/app/controller/module/profile.php | 54 - src/app/controller/module/search.php | 24 - src/app/controller/page.php | 428 - src/app/controller/response.php | 65 - src/app/controller/user.php | 117 - src/app/model/database.php | 1866 ---- src/app/model/locale.php | 37 - src/app/model/request.php | 104 - src/app/model/sphinx.php | 111 - src/app/model/validator.php | 2216 ---- src/app/model/website.php | 46 - src/app/view/theme/default/index.phtml | 32 - .../view/theme/default/module/footer.phtml | 27 - src/app/view/theme/default/module/head.phtml | 7 - .../view/theme/default/module/header.phtml | 10 - src/app/view/theme/default/module/page.phtml | 126 - .../theme/default/module/pagination.phtml | 15 - .../view/theme/default/module/search.phtml | 20 - .../view/theme/default/page/form/submit.phtml | 140 - src/app/view/theme/default/response.phtml | 24 - src/config/bootstrap.php | 160 - src/config/database.json | 7 - src/config/locales.json | 277 - src/config/memcached.json | 6 - src/config/moderators.json | 3 - src/config/nodes.json | 12 - src/config/peers.json | 7 - src/config/sphinx.json | 4 - src/config/themes.json | 3 - src/config/trackers.json | 23 - src/config/validator.json | 74 - src/config/website.json | 23 - src/crontab/export/feed.php | 558 - src/crontab/export/push.php | 506 - src/crontab/import/feed.php | 1193 -- src/crontab/scrape.php | 158 - src/crontab/sitemap.php | 86 - src/library/curl.php | 97 - src/library/environment.php | 27 - src/library/filter.php | 48 - src/library/scrapeer.php | 692 -- src/library/time.php | 45 - src/public/api/push.php | 938 -- src/public/index.php | 4 - symfony.lock | 279 + templates/base.html.twig | 16 + templates/default/home/index.html.twig | 2 + templates/default/layout.html.twig | 60 + templates/default/page/submit.html.twig | 129 + templates/default/profile/index.html.twig | 2 + .../default/profile/module.html.twig | 181 +- templates/default/profile/setting.html.twig | 2 + templates/default/search/index.html.twig | 10 + templates/default/search/module.html.twig | 4 + tests/bootstrap.php | 11 + translations/.gitignore | 0 114 files changed, 11523 insertions(+), 10996 deletions(-) create mode 100644 .env create mode 100644 .env.test create mode 100755 bin/console create mode 100755 bin/phpunit create mode 100644 composer.lock create mode 100644 config/bundles.php create mode 100644 config/packages/cache.yaml create mode 100644 config/packages/debug.yaml create mode 100644 config/packages/doctrine.yaml create mode 100644 config/packages/doctrine_migrations.yaml create mode 100644 config/packages/framework.yaml create mode 100644 config/packages/mailer.yaml create mode 100644 config/packages/messenger.yaml create mode 100644 config/packages/monolog.yaml create mode 100644 config/packages/notifier.yaml create mode 100644 config/packages/routing.yaml create mode 100644 config/packages/security.yaml create mode 100644 config/packages/translation.yaml create mode 100644 config/packages/twig.yaml create mode 100644 config/packages/validator.yaml create mode 100644 config/packages/web_profiler.yaml create mode 100644 config/preload.php create mode 100644 config/routes.yaml create mode 100644 config/routes/framework.yaml create mode 100644 config/routes/web_profiler.yaml create mode 100644 config/services.yaml delete mode 100644 database/yggtracker.mwb create mode 100644 docker-compose.override.yml create mode 100644 docker-compose.yml delete mode 100644 example/environment/crontab delete mode 100644 example/environment/nginx delete mode 100644 example/environment/sphinx.conf rename src/storage/log/index.html => migrations/.gitignore (100%) create mode 100644 phpunit.xml.dist rename {src/public/assets/theme => public/asset}/default/css/common.css (100%) rename {src/public/assets/theme => public/asset}/default/css/framework.css (88%) create mode 100644 public/index.php create mode 100644 src/Controller/.gitignore create mode 100644 src/Controller/HomeController.php create mode 100644 src/Controller/PageController.php create mode 100644 src/Controller/ProfileController.php create mode 100644 src/Controller/SearchController.php create mode 100644 src/Entity/.gitignore create mode 100644 src/Entity/Page.php create mode 100644 src/Entity/User.php create mode 100644 src/Kernel.php create mode 100644 src/Repository/.gitignore create mode 100644 src/Repository/PageRepository.php create mode 100644 src/Repository/UserRepository.php create mode 100644 src/Service/User.php delete mode 100644 src/app/controller/index.php delete mode 100644 src/app/controller/module/footer.php delete mode 100644 src/app/controller/module/head.php delete mode 100644 src/app/controller/module/header.php delete mode 100644 src/app/controller/module/page.php delete mode 100644 src/app/controller/module/pagination.php delete mode 100644 src/app/controller/module/profile.php delete mode 100644 src/app/controller/module/search.php delete mode 100644 src/app/controller/page.php delete mode 100644 src/app/controller/response.php delete mode 100644 src/app/controller/user.php delete mode 100644 src/app/model/database.php delete mode 100644 src/app/model/locale.php delete mode 100644 src/app/model/request.php delete mode 100644 src/app/model/sphinx.php delete mode 100644 src/app/model/validator.php delete mode 100644 src/app/model/website.php delete mode 100644 src/app/view/theme/default/index.phtml delete mode 100644 src/app/view/theme/default/module/footer.phtml delete mode 100644 src/app/view/theme/default/module/head.phtml delete mode 100644 src/app/view/theme/default/module/header.phtml delete mode 100644 src/app/view/theme/default/module/page.phtml delete mode 100644 src/app/view/theme/default/module/pagination.phtml delete mode 100644 src/app/view/theme/default/module/search.phtml delete mode 100644 src/app/view/theme/default/page/form/submit.phtml delete mode 100644 src/app/view/theme/default/response.phtml delete mode 100644 src/config/bootstrap.php delete mode 100644 src/config/database.json delete mode 100644 src/config/locales.json delete mode 100644 src/config/memcached.json delete mode 100644 src/config/moderators.json delete mode 100644 src/config/nodes.json delete mode 100644 src/config/peers.json delete mode 100644 src/config/sphinx.json delete mode 100644 src/config/themes.json delete mode 100644 src/config/trackers.json delete mode 100644 src/config/validator.json delete mode 100644 src/config/website.json delete mode 100644 src/crontab/export/feed.php delete mode 100644 src/crontab/export/push.php delete mode 100644 src/crontab/import/feed.php delete mode 100644 src/crontab/scrape.php delete mode 100644 src/crontab/sitemap.php delete mode 100644 src/library/curl.php delete mode 100644 src/library/environment.php delete mode 100644 src/library/filter.php delete mode 100644 src/library/scrapeer.php delete mode 100644 src/library/time.php delete mode 100644 src/public/api/push.php delete mode 100644 src/public/index.php create mode 100644 symfony.lock create mode 100644 templates/base.html.twig create mode 100644 templates/default/home/index.html.twig create mode 100644 templates/default/layout.html.twig create mode 100644 templates/default/page/submit.html.twig create mode 100644 templates/default/profile/index.html.twig rename src/app/view/theme/default/module/profile.phtml => templates/default/profile/module.html.twig (52%) create mode 100644 templates/default/profile/setting.html.twig create mode 100644 templates/default/search/index.html.twig create mode 100644 templates/default/search/module.html.twig create mode 100644 tests/bootstrap.php create mode 100644 translations/.gitignore diff --git a/.env b/.env new file mode 100644 index 0000000..ff72acd --- /dev/null +++ b/.env @@ -0,0 +1,50 @@ +# In all environments, the following files are loaded if they exist, +# the latter taking precedence over the former: +# +# * .env contains default values for the environment variables needed by the app +# * .env.local uncommitted file with local overrides +# * .env.$APP_ENV committed environment-specific defaults +# * .env.$APP_ENV.local uncommitted environment-specific overrides +# +# Real environment variables win over .env files. +# +# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. +# https://symfony.com/doc/current/configuration/secrets.html +# +# 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 + +###> symfony/framework-bundle ### +APP_ENV=dev +APP_SECRET=EDITME +###< symfony/framework-bundle ### + +###> doctrine/doctrine-bundle ### +# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url +# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml +# +DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db" +# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4" +# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4" +# DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=15&charset=utf8" +###< doctrine/doctrine-bundle ### + +###> symfony/messenger ### +# Choose one of the transports below +# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages +# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages +MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0 +###< symfony/messenger ### + +###> symfony/mailer ### +# MAILER_DSN=null://null +###< symfony/mailer ### + +###> symfony/crowdin-translation-provider ### +# CROWDIN_DSN=crowdin://PROJECT_ID:API_TOKEN@ORGANIZATION_DOMAIN.default +###< symfony/crowdin-translation-provider ### + +# YGGtracker +APP_VERSION='2.0.0' + +APP_NAME=YGGtracker \ No newline at end of file diff --git a/.env.test b/.env.test new file mode 100644 index 0000000..9e7162f --- /dev/null +++ b/.env.test @@ -0,0 +1,6 @@ +# define your env variables for the test env here +KERNEL_CLASS='App\Kernel' +APP_SECRET='$ecretf0rt3st' +SYMFONY_DEPRECATIONS_HELPER=999999 +PANTHER_APP_ENV=panther +PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots diff --git a/.gitignore b/.gitignore index febfe8f..79ced3c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,30 +1,22 @@ -/.vscode/ +###> symfony/framework-bundle ### +/.env.local +/.env.local.php +/.env.*.local +/config/secrets/prod/prod.decrypt.private.php +/public/bundles/ +/var/ /vendor/ +###< symfony/framework-bundle ### -/database/* -!/database/yggtracker.mwb +###> phpunit/phpunit ### +/phpunit.xml +.phpunit.result.cache +###< phpunit/phpunit ### -/src/public/api/*.json +###> symfony/phpunit-bridge ### +.phpunit.result.cache +/phpunit.xml +###< symfony/phpunit-bridge ### -/src/config/* -!/src/config/bootstrap.php -!/src/config/website.json -!/src/config/locales.json -!/src/config/themes.json -!/src/config/sphinx.json -!/src/config/memcached.json -!/src/config/database.json -!/src/config/validator.json -!/src/config/moderators.json -!/src/config/nodes.json -!/src/config/trackers.json -!/src/config/peers.json - -/src/public/sitemap.xml - -/src/storage/log/*.log - -/composer.lock - -*test* \ No newline at end of file +.vscode \ No newline at end of file diff --git a/bin/console b/bin/console new file mode 100755 index 0000000..c933dc5 --- /dev/null +++ b/bin/console @@ -0,0 +1,17 @@ +#!/usr/bin/env php +=0.3.0", - "yggverse/parser": ">=0.4.0", + "php": ">=8.1", + "ext-ctype": "*", + "ext-iconv": "*", + "christeredvartsen/php-bittorrent": "^2.0", + "doctrine/annotations": "^2.0", + "doctrine/doctrine-bundle": "^2.10", + "doctrine/doctrine-migrations-bundle": "^3.2", + "doctrine/orm": "^2.16", "jdenticon/jdenticon": "^1.0", - "christeredvartsen/php-bittorrent": "^2.0" + "phpdocumentor/reflection-docblock": "^5.3", + "phpstan/phpdoc-parser": "^1.24", + "symfony/asset": "6.3.*", + "symfony/console": "6.3.*", + "symfony/crowdin-translation-provider": "6.3.*", + "symfony/doctrine-messenger": "6.3.*", + "symfony/dotenv": "6.3.*", + "symfony/expression-language": "6.3.*", + "symfony/flex": "^2", + "symfony/form": "6.3.*", + "symfony/framework-bundle": "6.3.*", + "symfony/http-client": "6.3.*", + "symfony/intl": "6.3.*", + "symfony/mailer": "6.3.*", + "symfony/mime": "6.3.*", + "symfony/monolog-bundle": "^3.0", + "symfony/notifier": "6.3.*", + "symfony/process": "6.3.*", + "symfony/property-access": "6.3.*", + "symfony/property-info": "6.3.*", + "symfony/runtime": "6.3.*", + "symfony/security-bundle": "6.3.*", + "symfony/serializer": "6.3.*", + "symfony/string": "6.3.*", + "symfony/translation": "6.3.*", + "symfony/twig-bundle": "6.3.*", + "symfony/validator": "6.3.*", + "symfony/web-link": "6.3.*", + "symfony/yaml": "6.3.*", + "twig/extra-bundle": "^2.12|^3.0", + "twig/twig": "^2.12|^3.0" + }, + "config": { + "allow-plugins": { + "php-http/discovery": true, + "symfony/flex": true, + "symfony/runtime": true + }, + "sort-packages": true }, - "license": "MIT", "autoload": { "psr-4": { - "Yggverse\\Yggtracker\\": "src/" + "App\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "App\\Tests\\": "tests/" } }, - "authors": [ - { - "name": "YGGverse" + "replace": { + "symfony/polyfill-ctype": "*", + "symfony/polyfill-iconv": "*", + "symfony/polyfill-php72": "*", + "symfony/polyfill-php73": "*", + "symfony/polyfill-php74": "*", + "symfony/polyfill-php80": "*", + "symfony/polyfill-php81": "*" + }, + "scripts": { + "auto-scripts": { + "cache:clear": "symfony-cmd", + "assets:install %PUBLIC_DIR%": "symfony-cmd" + }, + "post-install-cmd": [ + "@auto-scripts" + ], + "post-update-cmd": [ + "@auto-scripts" + ] + }, + "conflict": { + "symfony/symfony": "*" + }, + "extra": { + "symfony": { + "allow-contrib": false, + "require": "6.3.*" } - ], - "minimum-stability": "alpha" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "symfony/browser-kit": "6.3.*", + "symfony/css-selector": "6.3.*", + "symfony/debug-bundle": "6.3.*", + "symfony/maker-bundle": "^1.0", + "symfony/phpunit-bridge": "^6.3", + "symfony/stopwatch": "6.3.*", + "symfony/web-profiler-bundle": "6.3.*" + } } diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..2f8b33c --- /dev/null +++ b/composer.lock @@ -0,0 +1,9748 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "12e4a495651b5797393aa13acc4d132f", + "packages": [ + { + "name": "christeredvartsen/php-bittorrent", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/christeredvartsen/php-bittorrent.git", + "reference": "1e4f17ef840cd56b10e9c507df0064048fc91778" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/christeredvartsen/php-bittorrent/zipball/1e4f17ef840cd56b10e9c507df0064048fc91778", + "reference": "1e4f17ef840cd56b10e9c507df0064048fc91778", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "require-dev": { + "phploc/phploc": "^5.0", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "BitTorrent\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christer Edvartsen", + "email": "cogo@starzinger.net" + } + ], + "description": "A set of components that can be used to interact with torrent files (read+write) and classes that can encode/decode to/from the BitTorrent format.", + "homepage": "https://github.com/christeredvartsen/php-bittorrent", + "keywords": [ + "bittorrent", + "torrent" + ], + "support": { + "issues": "https://github.com/christeredvartsen/php-bittorrent/issues", + "source": "https://github.com/christeredvartsen/php-bittorrent" + }, + "time": "2020-01-21T19:12:01+00:00" + }, + { + "name": "doctrine/annotations", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f", + "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2 || ^3", + "ext-tokenizer": "*", + "php": "^7.2 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^2.0", + "doctrine/coding-standard": "^10", + "phpstan/phpstan": "^1.8.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "symfony/cache": "^5.4 || ^6", + "vimeo/psalm": "^4.10" + }, + "suggest": { + "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/2.0.1" + }, + "time": "2023-02-02T22:02:53+00:00" + }, + { + "name": "doctrine/cache", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "1ca8f21980e770095a31456042471a57bc4c68fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb", + "reference": "1ca8f21980e770095a31456042471a57bc4c68fb", + "shasum": "" + }, + "require": { + "php": "~7.1 || ^8.0" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "symfony/cache": "^4.4 || ^5.4 || ^6", + "symfony/var-exporter": "^4.4 || ^5.4 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", + "homepage": "https://www.doctrine-project.org/projects/cache.html", + "keywords": [ + "abstraction", + "apcu", + "cache", + "caching", + "couchdb", + "memcached", + "php", + "redis", + "xcache" + ], + "support": { + "issues": "https://github.com/doctrine/cache/issues", + "source": "https://github.com/doctrine/cache/tree/2.2.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache", + "type": "tidelift" + } + ], + "time": "2022-05-20T20:07:39+00:00" + }, + { + "name": "doctrine/collections", + "version": "2.1.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "3023e150f90a38843856147b58190aa8b46cc155" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/3023e150f90a38843856147b58190aa8b46cc155", + "reference": "3023e150f90a38843856147b58190aa8b46cc155", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1", + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^10.0", + "ext-json": "*", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^5.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Collections\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", + "homepage": "https://www.doctrine-project.org/projects/collections.html", + "keywords": [ + "array", + "collections", + "iterators", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/collections/issues", + "source": "https://github.com/doctrine/collections/tree/2.1.3" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcollections", + "type": "tidelift" + } + ], + "time": "2023-07-06T15:15:36+00:00" + }, + { + "name": "doctrine/common", + "version": "3.4.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/common.git", + "reference": "8b5e5650391f851ed58910b3e3d48a71062eeced" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/common/zipball/8b5e5650391f851ed58910b3e3d48a71062eeced", + "reference": "8b5e5650391f851ed58910b3e3d48a71062eeced", + "shasum": "" + }, + "require": { + "doctrine/persistence": "^2.0 || ^3.0", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0 || ^10.0", + "doctrine/collections": "^1", + "phpstan/phpstan": "^1.4.1", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5.20 || ^8.5 || ^9.0", + "squizlabs/php_codesniffer": "^3.0", + "symfony/phpunit-bridge": "^6.1", + "vimeo/psalm": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, proxies and much more.", + "homepage": "https://www.doctrine-project.org/projects/common.html", + "keywords": [ + "common", + "doctrine", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/common/issues", + "source": "https://github.com/doctrine/common/tree/3.4.3" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcommon", + "type": "tidelift" + } + ], + "time": "2022-10-09T11:47:59+00:00" + }, + { + "name": "doctrine/dbal", + "version": "3.7.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/dbal.git", + "reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/00d03067f07482f025d41ab55e4ba0db5eca2cdf", + "reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2", + "doctrine/cache": "^1.11|^2.0", + "doctrine/deprecations": "^0.5.3|^1", + "doctrine/event-manager": "^1|^2", + "php": "^7.4 || ^8.0", + "psr/cache": "^1|^2|^3", + "psr/log": "^1|^2|^3" + }, + "require-dev": { + "doctrine/coding-standard": "12.0.0", + "fig/log-test": "^1", + "jetbrains/phpstorm-stubs": "2023.1", + "phpstan/phpstan": "1.10.35", + "phpstan/phpstan-strict-rules": "^1.5", + "phpunit/phpunit": "9.6.13", + "psalm/plugin-phpunit": "0.18.4", + "slevomat/coding-standard": "8.13.1", + "squizlabs/php_codesniffer": "3.7.2", + "symfony/cache": "^5.4|^6.0", + "symfony/console": "^4.4|^5.4|^6.0", + "vimeo/psalm": "4.30.0" + }, + "suggest": { + "symfony/console": "For helpful console commands such as SQL execution and import of files." + }, + "bin": [ + "bin/doctrine-dbal" + ], + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\DBAL\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.", + "homepage": "https://www.doctrine-project.org/projects/dbal.html", + "keywords": [ + "abstraction", + "database", + "db2", + "dbal", + "mariadb", + "mssql", + "mysql", + "oci8", + "oracle", + "pdo", + "pgsql", + "postgresql", + "queryobject", + "sasql", + "sql", + "sqlite", + "sqlserver", + "sqlsrv" + ], + "support": { + "issues": "https://github.com/doctrine/dbal/issues", + "source": "https://github.com/doctrine/dbal/tree/3.7.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal", + "type": "tidelift" + } + ], + "time": "2023-09-26T20:56:55+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931", + "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.2" + }, + "time": "2023-09-27T20:04:15+00:00" + }, + { + "name": "doctrine/doctrine-bundle", + "version": "2.10.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineBundle.git", + "reference": "f28b1f78de3a2938ff05cfe751233097624cc756" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/f28b1f78de3a2938ff05cfe751233097624cc756", + "reference": "f28b1f78de3a2938ff05cfe751233097624cc756", + "shasum": "" + }, + "require": { + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/dbal": "^3.6.0", + "doctrine/persistence": "^2.2 || ^3", + "doctrine/sql-formatter": "^1.0.1", + "php": "^7.4 || ^8.0", + "symfony/cache": "^5.4 || ^6.0", + "symfony/config": "^5.4 || ^6.0", + "symfony/console": "^5.4 || ^6.0", + "symfony/dependency-injection": "^5.4 || ^6.0", + "symfony/deprecation-contracts": "^2.1 || ^3", + "symfony/doctrine-bridge": "^5.4.19 || ^6.0.7", + "symfony/framework-bundle": "^5.4 || ^6.0", + "symfony/service-contracts": "^1.1.1 || ^2.0 || ^3" + }, + "conflict": { + "doctrine/annotations": ">=3.0", + "doctrine/orm": "<2.11 || >=3.0", + "twig/twig": "<1.34 || >=2.0 <2.4" + }, + "require-dev": { + "doctrine/annotations": "^1 || ^2", + "doctrine/coding-standard": "^9.0", + "doctrine/deprecations": "^1.0", + "doctrine/orm": "^2.11 || ^3.0", + "friendsofphp/proxy-manager-lts": "^1.0", + "phpunit/phpunit": "^9.5.26 || ^10.0", + "psalm/plugin-phpunit": "^0.18.4", + "psalm/plugin-symfony": "^4", + "psr/log": "^1.1.4 || ^2.0 || ^3.0", + "symfony/phpunit-bridge": "^6.1", + "symfony/property-info": "^5.4 || ^6.0", + "symfony/proxy-manager-bridge": "^5.4 || ^6.0", + "symfony/security-bundle": "^5.4 || ^6.0", + "symfony/twig-bridge": "^5.4 || ^6.0", + "symfony/validator": "^5.4 || ^6.0", + "symfony/web-profiler-bundle": "^5.4 || ^6.0", + "symfony/yaml": "^5.4 || ^6.0", + "twig/twig": "^1.34 || ^2.12 || ^3.0", + "vimeo/psalm": "^4.30" + }, + "suggest": { + "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.", + "ext-pdo": "*", + "symfony/web-profiler-bundle": "To use the data collector." + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Doctrine\\Bundle\\DoctrineBundle\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + }, + { + "name": "Doctrine Project", + "homepage": "https://www.doctrine-project.org/" + } + ], + "description": "Symfony DoctrineBundle", + "homepage": "https://www.doctrine-project.org", + "keywords": [ + "database", + "dbal", + "orm", + "persistence" + ], + "support": { + "issues": "https://github.com/doctrine/DoctrineBundle/issues", + "source": "https://github.com/doctrine/DoctrineBundle/tree/2.10.2" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdoctrine-bundle", + "type": "tidelift" + } + ], + "time": "2023-08-06T09:31:40+00:00" + }, + { + "name": "doctrine/doctrine-migrations-bundle", + "version": "3.2.4", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineMigrationsBundle.git", + "reference": "94e6b0fe1a50901d52f59dbb9b4b0737718b2c1e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/94e6b0fe1a50901d52f59dbb9b4b0737718b2c1e", + "reference": "94e6b0fe1a50901d52f59dbb9b4b0737718b2c1e", + "shasum": "" + }, + "require": { + "doctrine/doctrine-bundle": "~1.0|~2.0", + "doctrine/migrations": "^3.2", + "php": "^7.2|^8.0", + "symfony/framework-bundle": "~3.4|~4.0|~5.0|~6.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "doctrine/orm": "^2.6", + "doctrine/persistence": "^1.3||^2.0", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-deprecation-rules": "^1", + "phpstan/phpstan-phpunit": "^1", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5|^9.5", + "vimeo/psalm": "^4.22" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Doctrine\\Bundle\\MigrationsBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Doctrine Project", + "homepage": "https://www.doctrine-project.org" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DoctrineMigrationsBundle", + "homepage": "https://www.doctrine-project.org", + "keywords": [ + "dbal", + "migrations", + "schema" + ], + "support": { + "issues": "https://github.com/doctrine/DoctrineMigrationsBundle/issues", + "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.2.4" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdoctrine-migrations-bundle", + "type": "tidelift" + } + ], + "time": "2023-06-02T08:19:26+00:00" + }, + { + "name": "doctrine/event-manager", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/event-manager.git", + "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/750671534e0241a7c50ea5b43f67e23eb5c96f32", + "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "conflict": { + "doctrine/common": "<2.9" + }, + "require-dev": { + "doctrine/coding-standard": "^10", + "phpstan/phpstan": "^1.8.8", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^4.28" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.", + "homepage": "https://www.doctrine-project.org/projects/event-manager.html", + "keywords": [ + "event", + "event dispatcher", + "event manager", + "event system", + "events" + ], + "support": { + "issues": "https://github.com/doctrine/event-manager/issues", + "source": "https://github.com/doctrine/event-manager/tree/2.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager", + "type": "tidelift" + } + ], + "time": "2022-10-12T20:59:15+00:00" + }, + { + "name": "doctrine/inflector", + "version": "2.0.8", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/f9301a5b2fb1216b2b08f02ba04dc45423db6bff", + "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^11.0", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^8.5 || ^9.5", + "vimeo/psalm": "^4.25 || ^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.0.8" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "time": "2023-06-16T13:40:37+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:23:10+00:00" + }, + { + "name": "doctrine/lexer", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^10", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^4.11 || ^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/2.1.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2022-12-14T08:49:07+00:00" + }, + { + "name": "doctrine/migrations", + "version": "3.6.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/migrations.git", + "reference": "e542ad8bcd606d7a18d0875babb8a6d963c9c059" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/migrations/zipball/e542ad8bcd606d7a18d0875babb8a6d963c9c059", + "reference": "e542ad8bcd606d7a18d0875babb8a6d963c9c059", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2", + "doctrine/dbal": "^3.5.1", + "doctrine/deprecations": "^0.5.3 || ^1", + "doctrine/event-manager": "^1.2 || ^2.0", + "php": "^8.1", + "psr/log": "^1.1.3 || ^2 || ^3", + "symfony/console": "^4.4.16 || ^5.4 || ^6.0", + "symfony/stopwatch": "^4.4 || ^5.4 || ^6.0", + "symfony/var-exporter": "^6.2" + }, + "conflict": { + "doctrine/orm": "<2.12" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "doctrine/orm": "^2.13", + "doctrine/persistence": "^2 || ^3", + "doctrine/sql-formatter": "^1.0", + "ext-pdo_sqlite": "*", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-deprecation-rules": "^1", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.1", + "phpstan/phpstan-symfony": "^1.1", + "phpunit/phpunit": "^9.5.24", + "symfony/cache": "^4.4 || ^5.4 || ^6.0", + "symfony/process": "^4.4 || ^5.4 || ^6.0", + "symfony/yaml": "^4.4 || ^5.4 || ^6.0" + }, + "suggest": { + "doctrine/sql-formatter": "Allows to generate formatted SQL with the diff command.", + "symfony/yaml": "Allows the use of yaml for migration configuration files." + }, + "bin": [ + "bin/doctrine-migrations" + ], + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Migrations\\": "lib/Doctrine/Migrations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Michael Simonson", + "email": "contact@mikesimonson.com" + } + ], + "description": "PHP Doctrine Migrations project offer additional functionality on top of the database abstraction layer (DBAL) for versioning your database schema and easily deploying changes to it. It is a very easy to use and a powerful tool.", + "homepage": "https://www.doctrine-project.org/projects/migrations.html", + "keywords": [ + "database", + "dbal", + "migrations" + ], + "support": { + "issues": "https://github.com/doctrine/migrations/issues", + "source": "https://github.com/doctrine/migrations/tree/3.6.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fmigrations", + "type": "tidelift" + } + ], + "time": "2023-02-15T18:49:46+00:00" + }, + { + "name": "doctrine/orm", + "version": "2.16.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/orm.git", + "reference": "17500f56eaa930f5cd14d765bc2cd851c7d37cc0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/orm/zipball/17500f56eaa930f5cd14d765bc2cd851c7d37cc0", + "reference": "17500f56eaa930f5cd14d765bc2cd851c7d37cc0", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2", + "doctrine/cache": "^1.12.1 || ^2.1.1", + "doctrine/collections": "^1.5 || ^2.1", + "doctrine/common": "^3.0.3", + "doctrine/dbal": "^2.13.1 || ^3.2", + "doctrine/deprecations": "^0.5.3 || ^1", + "doctrine/event-manager": "^1.2 || ^2", + "doctrine/inflector": "^1.4 || ^2.0", + "doctrine/instantiator": "^1.3 || ^2", + "doctrine/lexer": "^2", + "doctrine/persistence": "^2.4 || ^3", + "ext-ctype": "*", + "php": "^7.1 || ^8.0", + "psr/cache": "^1 || ^2 || ^3", + "symfony/console": "^4.2 || ^5.0 || ^6.0", + "symfony/polyfill-php72": "^1.23", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "doctrine/annotations": "<1.13 || >= 3.0" + }, + "require-dev": { + "doctrine/annotations": "^1.13 || ^2", + "doctrine/coding-standard": "^9.0.2 || ^12.0", + "phpbench/phpbench": "^0.16.10 || ^1.0", + "phpstan/phpstan": "~1.4.10 || 1.10.28", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6", + "psr/log": "^1 || ^2 || ^3", + "squizlabs/php_codesniffer": "3.7.2", + "symfony/cache": "^4.4 || ^5.4 || ^6.0", + "symfony/var-exporter": "^4.4 || ^5.4 || ^6.2", + "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0", + "vimeo/psalm": "4.30.0 || 5.14.1" + }, + "suggest": { + "ext-dom": "Provides support for XSD validation for XML mapping files", + "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0", + "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" + }, + "bin": [ + "bin/doctrine" + ], + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\ORM\\": "lib/Doctrine/ORM" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Object-Relational-Mapper for PHP", + "homepage": "https://www.doctrine-project.org/projects/orm.html", + "keywords": [ + "database", + "orm" + ], + "support": { + "issues": "https://github.com/doctrine/orm/issues", + "source": "https://github.com/doctrine/orm/tree/2.16.2" + }, + "time": "2023-08-27T18:21:56+00:00" + }, + { + "name": "doctrine/persistence", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/persistence.git", + "reference": "63fee8c33bef740db6730eb2a750cd3da6495603" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/63fee8c33bef740db6730eb2a750cd3da6495603", + "reference": "63fee8c33bef740db6730eb2a750cd3da6495603", + "shasum": "" + }, + "require": { + "doctrine/event-manager": "^1 || ^2", + "php": "^7.2 || ^8.0", + "psr/cache": "^1.0 || ^2.0 || ^3.0" + }, + "conflict": { + "doctrine/common": "<2.10" + }, + "require-dev": { + "composer/package-versions-deprecated": "^1.11", + "doctrine/coding-standard": "^11", + "doctrine/common": "^3.0", + "phpstan/phpstan": "1.9.4", + "phpstan/phpstan-phpunit": "^1", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5 || ^9.5", + "symfony/cache": "^4.4 || ^5.4 || ^6.0", + "vimeo/psalm": "4.30.0 || 5.3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Persistence\\": "src/Persistence" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.", + "homepage": "https://www.doctrine-project.org/projects/persistence.html", + "keywords": [ + "mapper", + "object", + "odm", + "orm", + "persistence" + ], + "support": { + "issues": "https://github.com/doctrine/persistence/issues", + "source": "https://github.com/doctrine/persistence/tree/3.2.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fpersistence", + "type": "tidelift" + } + ], + "time": "2023-05-17T18:32:04+00:00" + }, + { + "name": "doctrine/sql-formatter", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/sql-formatter.git", + "reference": "25a06c7bf4c6b8218f47928654252863ffc890a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/25a06c7bf4c6b8218f47928654252863ffc890a5", + "reference": "25a06c7bf4c6b8218f47928654252863ffc890a5", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4" + }, + "bin": [ + "bin/sql-formatter" + ], + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\SqlFormatter\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Dorn", + "email": "jeremy@jeremydorn.com", + "homepage": "https://jeremydorn.com/" + } + ], + "description": "a PHP SQL highlighting library", + "homepage": "https://github.com/doctrine/sql-formatter/", + "keywords": [ + "highlight", + "sql" + ], + "support": { + "issues": "https://github.com/doctrine/sql-formatter/issues", + "source": "https://github.com/doctrine/sql-formatter/tree/1.1.3" + }, + "time": "2022-05-23T21:33:49+00:00" + }, + { + "name": "egulias/email-validator", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "3a85486b709bc384dae8eb78fb2eec649bdb64ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/3a85486b709bc384dae8eb78fb2eec649bdb64ff", + "reference": "3a85486b709bc384dae8eb78fb2eec649bdb64ff", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" + }, + "require-dev": { + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^4.30" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2023-01-14T14:17:03+00:00" + }, + { + "name": "jdenticon/jdenticon", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/dmester/jdenticon-php.git", + "reference": "cabb7a44c413c318392a341c5d3ca30fcdd57a6f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dmester/jdenticon-php/zipball/cabb7a44c413c318392a341c5d3ca30fcdd57a6f", + "reference": "cabb7a44c413c318392a341c5d3ca30fcdd57a6f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Jdenticon\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Mester Pirttijärvi" + } + ], + "description": "Render PNG and SVG identicons.", + "homepage": "https://jdenticon.com/", + "keywords": [ + "avatar", + "identicon", + "jdenticon" + ], + "support": { + "docs": "https://jdenticon.com/php-api.html", + "issues": "https://github.com/dmester/jdenticon-php/issues", + "source": "https://github.com/dmester/jdenticon-php" + }, + "time": "2022-10-30T17:15:02+00:00" + }, + { + "name": "monolog/monolog", + "version": "3.4.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "e2392369686d420ca32df3803de28b5d6f76867d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/e2392369686d420ca32df3803de28b5d6f76867d", + "reference": "e2392369686d420ca32df3803de28b5d6f76867d", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.4", + "phpunit/phpunit": "^10.1", + "predis/predis": "^1.1 || ^2", + "ruflin/elastica": "^7", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/3.4.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2023-06-21T08:46:11+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + }, + "time": "2021-10-19T17:43:47+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.7.3", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419", + "reference": "3219c6ee25c9ea71e3d9bbaf39c67c9ebd499419", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "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.7.3" + }, + "time": "2023-08-12T11:01:26+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.24.2", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "bcad8d995980440892759db0c32acae7c8e79442" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bcad8d995980440892759db0c32acae7c8e79442", + "reference": "bcad8d995980440892759db0c32acae7c8e79442", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.2" + }, + "time": "2023-09-26T12:28:12+00:00" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/link", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/link.git", + "reference": "84b159194ecfd7eaa472280213976e96415433f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/link/zipball/84b159194ecfd7eaa472280213976e96415433f7", + "reference": "84b159194ecfd7eaa472280213976e96415433f7", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "suggest": { + "fig/link-util": "Provides some useful PSR-13 utilities" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Link\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for HTTP links", + "homepage": "https://github.com/php-fig/link", + "keywords": [ + "http", + "http-link", + "link", + "psr", + "psr-13", + "rest" + ], + "support": { + "source": "https://github.com/php-fig/link/tree/2.0.1" + }, + "time": "2021-03-11T23:00:27+00:00" + }, + { + "name": "psr/log", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "time": "2021-07-14T16:46:02+00:00" + }, + { + "name": "symfony/asset", + "version": "v6.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/asset.git", + "reference": "b77a4cc8e266b7e0db688de740f9ee7253aa411c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/asset/zipball/b77a4cc8e266b7e0db688de740f9ee7253aa411c", + "reference": "b77a4cc8e266b7e0db688de740f9ee7253aa411c", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "conflict": { + "symfony/http-foundation": "<5.4" + }, + "require-dev": { + "symfony/http-client": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Asset\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/asset/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-04-21T14:41:17+00:00" + }, + { + "name": "symfony/cache", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "6c1a3ea078c4d88ee892530945df63a87981b2da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/6c1a3ea078c4d88ee892530945df63a87981b2da", + "reference": "6c1a3ea078c4d88ee892530945df63a87981b2da", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/cache": "^2.0|^3.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^2.5|^3", + "symfony/service-contracts": "^2.5|^3", + "symfony/var-exporter": "^6.2.10" + }, + "conflict": { + "doctrine/dbal": "<2.13.1", + "symfony/dependency-injection": "<5.4", + "symfony/http-kernel": "<5.4", + "symfony/var-dumper": "<5.4" + }, + "provide": { + "psr/cache-implementation": "2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0", + "symfony/cache-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/dbal": "^2.13.1|^3.0", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/filesystem": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/messenger": "^5.4|^6.0", + "symfony/var-dumper": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "classmap": [ + "Traits/ValueWrapper.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-26T15:48:55+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v3.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "ad945640ccc0ae6e208bcea7d7de4b39b569896b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/ad945640ccc0ae6e208bcea7d7de4b39b569896b", + "reference": "ad945640ccc0ae6e208bcea7d7de4b39b569896b", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/cache": "^3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v3.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-23T14:45:45+00:00" + }, + { + "name": "symfony/clock", + "version": "v6.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/clock.git", + "reference": "a74086d3db70d0f06ffd84480daa556248706e98" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/clock/zipball/a74086d3db70d0f06ffd84480daa556248706e98", + "reference": "a74086d3db70d0f06ffd84480daa556248706e98", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/clock": "^1.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v6.3.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-31T11:35:03+00:00" + }, + { + "name": "symfony/config", + "version": "v6.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "b47ca238b03e7b0d7880ffd1cf06e8d637ca1467" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/b47ca238b03e7b0d7880ffd1cf06e8d637ca1467", + "reference": "b47ca238b03e7b0d7880ffd1cf06e8d637ca1467", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^5.4|^6.0", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<5.4", + "symfony/service-contracts": "<2.5" + }, + "require-dev": { + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", + "symfony/messenger": "^5.4|^6.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v6.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-19T20:22:16+00:00" + }, + { + "name": "symfony/console", + "version": "v6.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/eca495f2ee845130855ddf1cf18460c38966c8b6", + "reference": "eca495f2ee845130855ddf1cf18460c38966c8b6", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/lock": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/var-dumper": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v6.3.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-08-16T10:10:12+00:00" + }, + { + "name": "symfony/crowdin-translation-provider", + "version": "v6.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/crowdin-translation-provider.git", + "reference": "dea8d5a664780e9c36efc075fa758d435e4ef3a7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/crowdin-translation-provider/zipball/dea8d5a664780e9c36efc075fa758d435e4ef3a7", + "reference": "dea8d5a664780e9c36efc075fa758d435e4ef3a7", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/config": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/translation": "^5.4.21|^6.2.7" + }, + "type": "symfony-translation-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Translation\\Bridge\\Crowdin\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrii Bodnar", + "homepage": "https://github.com/andrii-bodnar" + }, + { + "name": "Mathieu Santostefano", + "homepage": "https://github.com/welcomattic" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Crowdin Translation Provider Bridge", + "homepage": "https://symfony.com", + "keywords": [ + "crowdin", + "provider", + "translation" + ], + "support": { + "source": "https://github.com/symfony/crowdin-translation-provider/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-04-20T13:15:31+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "2ed62b3bf98346e1f45529a7b6be2196739bb993" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/2ed62b3bf98346e1f45529a7b6be2196739bb993", + "reference": "2ed62b3bf98346e1f45529a7b6be2196739bb993", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/service-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.2.10" + }, + "conflict": { + "ext-psr": "<1.1|>=2", + "symfony/config": "<6.1", + "symfony/finder": "<5.4", + "symfony/proxy-manager-bridge": "<6.3", + "symfony/yaml": "<5.4" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "symfony/service-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "symfony/config": "^6.1", + "symfony/expression-language": "^5.4|^6.0", + "symfony/yaml": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-25T16:46:40+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-23T14:45:45+00:00" + }, + { + "name": "symfony/doctrine-bridge", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/doctrine-bridge.git", + "reference": "9977eb1adf999ceded213e88c1ac6dff7a1a0306" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/9977eb1adf999ceded213e88c1ac6dff7a1a0306", + "reference": "9977eb1adf999ceded213e88c1ac6dff7a1a0306", + "shasum": "" + }, + "require": { + "doctrine/event-manager": "^1.2|^2", + "doctrine/persistence": "^2|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "doctrine/annotations": "<1.13.1", + "doctrine/dbal": "<2.13.1", + "doctrine/lexer": "<1.1", + "doctrine/orm": "<2.12", + "symfony/cache": "<5.4", + "symfony/dependency-injection": "<6.2", + "symfony/form": "<5.4.21|>=6,<6.2.7", + "symfony/http-foundation": "<6.3", + "symfony/http-kernel": "<6.2", + "symfony/lock": "<6.3", + "symfony/messenger": "<5.4", + "symfony/property-info": "<5.4", + "symfony/security-bundle": "<5.4", + "symfony/security-core": "<6.0", + "symfony/validator": "<5.4.25|>=6,<6.2.12|>=6.3,<6.3.1" + }, + "require-dev": { + "doctrine/annotations": "^1.13.1|^2", + "doctrine/collections": "^1.0|^2.0", + "doctrine/data-fixtures": "^1.1", + "doctrine/dbal": "^2.13.1|^3.0", + "doctrine/orm": "^2.12", + "psr/log": "^1|^2|^3", + "symfony/cache": "^5.4|^6.0", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^6.2", + "symfony/doctrine-messenger": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/form": "^5.4.21|^6.2.7", + "symfony/http-kernel": "^6.3", + "symfony/lock": "^6.3", + "symfony/messenger": "^5.4|^6.0", + "symfony/property-access": "^5.4|^6.0", + "symfony/property-info": "^5.4|^6.0", + "symfony/proxy-manager-bridge": "^5.4|^6.0", + "symfony/security-core": "^6.0", + "symfony/stopwatch": "^5.4|^6.0", + "symfony/translation": "^5.4|^6.0", + "symfony/uid": "^5.4|^6.0", + "symfony/validator": "^5.4.25|~6.2.12|^6.3.1", + "symfony/var-dumper": "^5.4|^6.0" + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Doctrine\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Doctrine with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/doctrine-bridge/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-29T16:16:03+00:00" + }, + { + "name": "symfony/doctrine-messenger", + "version": "v6.3.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/doctrine-messenger.git", + "reference": "f1c253e24ae6d2bc4939b1439e074e6d2e73ecdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/f1c253e24ae6d2bc4939b1439e074e6d2e73ecdb", + "reference": "f1c253e24ae6d2bc4939b1439e074e6d2e73ecdb", + "shasum": "" + }, + "require": { + "doctrine/dbal": "^2.13|^3.0", + "php": ">=8.1", + "symfony/messenger": "^5.4|^6.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "doctrine/persistence": "<1.3" + }, + "require-dev": { + "doctrine/persistence": "^1.3|^2|^3", + "symfony/property-access": "^5.4|^6.0", + "symfony/serializer": "^5.4|^6.0" + }, + "type": "symfony-messenger-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\Bridge\\Doctrine\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Doctrine Messenger Bridge", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/doctrine-messenger/tree/v6.3.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-06-24T11:51:27+00:00" + }, + { + "name": "symfony/dotenv", + "version": "v6.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "ceadb434fe2a6763a03d2d110441745834f3dd1e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/ceadb434fe2a6763a03d2d110441745834f3dd1e", + "reference": "ceadb434fe2a6763a03d2d110441745834f3dd1e", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "conflict": { + "symfony/console": "<5.4", + "symfony/process": "<5.4" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Dotenv\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Registers environment variables from a .env file", + "homepage": "https://symfony.com", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "source": "https://github.com/symfony/dotenv/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-04-21T14:41:17+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "1f69476b64fb47105c06beef757766c376b548c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/1f69476b64fb47105c06beef757766c376b548c4", + "reference": "1f69476b64fb47105c06beef757766c376b548c4", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^1|^2|^3", + "symfony/var-dumper": "^5.4|^6.0" + }, + "conflict": { + "symfony/deprecation-contracts": "<2.5" + }, + "require-dev": { + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/serializer": "^5.4|^6.0" + }, + "bin": [ + "Resources/bin/patch-type-declarations" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-12T06:57:20+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v6.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/adb01fe097a4ee930db9258a3cc906b5beb5cf2e", + "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/error-handler": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v6.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-06T06:56:43+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "a76aed96a42d2b521153fb382d418e30d18b59df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df", + "reference": "a76aed96a42d2b521153fb382d418e30d18b59df", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-23T14:45:45+00:00" + }, + { + "name": "symfony/expression-language", + "version": "v6.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/expression-language.git", + "reference": "6d560c4c80e7e328708efd923f93ad67e6a0c1c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/6d560c4c80e7e328708efd923f93ad67e6a0c1c0", + "reference": "6d560c4c80e7e328708efd923f93ad67e6a0c1c0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/cache": "^5.4|^6.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/service-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ExpressionLanguage\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an engine that can compile and evaluate expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/expression-language/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-04-28T16:05:33+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v6.3.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", + "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v6.3.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-06-01T08:30:39+00:00" + }, + { + "name": "symfony/finder", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/a1b31d88c0e998168ca7792f222cbecee47428c4", + "reference": "a1b31d88c0e998168ca7792f222cbecee47428c4", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "symfony/filesystem": "^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-26T12:56:25+00:00" + }, + { + "name": "symfony/flex", + "version": "v2.3.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/flex.git", + "reference": "9c402af768c6c9f8126a9ffa192ecf7c16581e35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/flex/zipball/9c402af768c6c9f8126a9ffa192ecf7c16581e35", + "reference": "9c402af768c6c9f8126a9ffa192ecf7c16581e35", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.1", + "php": ">=8.0" + }, + "require-dev": { + "composer/composer": "^2.1", + "symfony/dotenv": "^5.4|^6.0", + "symfony/filesystem": "^5.4|^6.0", + "symfony/phpunit-bridge": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Flex\\Flex" + }, + "autoload": { + "psr-4": { + "Symfony\\Flex\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien.potencier@gmail.com" + } + ], + "description": "Composer plugin for Symfony", + "support": { + "issues": "https://github.com/symfony/flex/issues", + "source": "https://github.com/symfony/flex/tree/v2.3.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-08-04T09:02:35+00:00" + }, + { + "name": "symfony/form", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/form.git", + "reference": "0f9ad8600c1021983d096512066ee54332aa3139" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/form/zipball/0f9ad8600c1021983d096512066ee54332aa3139", + "reference": "0f9ad8600c1021983d096512066ee54332aa3139", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/options-resolver": "^5.4|^6.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/polyfill-mbstring": "~1.0", + "symfony/property-access": "^5.4|^6.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/console": "<5.4", + "symfony/dependency-injection": "<5.4", + "symfony/doctrine-bridge": "<5.4.21|>=6,<6.2.7", + "symfony/error-handler": "<5.4", + "symfony/framework-bundle": "<5.4", + "symfony/http-kernel": "<5.4", + "symfony/translation": "<5.4", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<6.3" + }, + "require-dev": { + "doctrine/collections": "^1.0|^2.0", + "symfony/config": "^5.4|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/html-sanitizer": "^6.1", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/intl": "^5.4|^6.0", + "symfony/security-core": "^6.2", + "symfony/security-csrf": "^5.4|^6.0", + "symfony/translation": "^5.4|^6.0", + "symfony/uid": "^5.4|^6.0", + "symfony/validator": "^5.4|^6.0", + "symfony/var-dumper": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Form\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows to easily create, process and reuse HTML forms", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/form/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-10T17:47:23+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "567cafcfc08e3076b47290a7558b0ca17a98b0ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/567cafcfc08e3076b47290a7558b0ca17a98b0ce", + "reference": "567cafcfc08e3076b47290a7558b0ca17a98b0ce", + "shasum": "" + }, + "require": { + "composer-runtime-api": ">=2.1", + "ext-xml": "*", + "php": ">=8.1", + "symfony/cache": "^5.4|^6.0", + "symfony/config": "^6.1", + "symfony/dependency-injection": "^6.3.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.1", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/filesystem": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", + "symfony/http-foundation": "^6.3", + "symfony/http-kernel": "^6.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/routing": "^5.4|^6.0" + }, + "conflict": { + "doctrine/annotations": "<1.13.1", + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/asset": "<5.4", + "symfony/clock": "<6.3", + "symfony/console": "<5.4", + "symfony/dom-crawler": "<6.3", + "symfony/dotenv": "<5.4", + "symfony/form": "<5.4", + "symfony/http-client": "<6.3", + "symfony/lock": "<5.4", + "symfony/mailer": "<5.4", + "symfony/messenger": "<6.3", + "symfony/mime": "<6.2", + "symfony/property-access": "<5.4", + "symfony/property-info": "<5.4", + "symfony/security-core": "<5.4", + "symfony/security-csrf": "<5.4", + "symfony/serializer": "<6.3", + "symfony/stopwatch": "<5.4", + "symfony/translation": "<6.2.8", + "symfony/twig-bridge": "<5.4", + "symfony/twig-bundle": "<5.4", + "symfony/validator": "<6.3", + "symfony/web-profiler-bundle": "<5.4", + "symfony/workflow": "<5.4" + }, + "require-dev": { + "doctrine/annotations": "^1.13.1|^2", + "doctrine/persistence": "^1.3|^2|^3", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^5.4|^6.0", + "symfony/asset-mapper": "^6.3", + "symfony/browser-kit": "^5.4|^6.0", + "symfony/clock": "^6.2", + "symfony/console": "^5.4.9|^6.0.9", + "symfony/css-selector": "^5.4|^6.0", + "symfony/dom-crawler": "^6.3", + "symfony/dotenv": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/form": "^5.4|^6.0", + "symfony/html-sanitizer": "^6.1", + "symfony/http-client": "^6.3", + "symfony/lock": "^5.4|^6.0", + "symfony/mailer": "^5.4|^6.0", + "symfony/messenger": "^6.3", + "symfony/mime": "^6.2", + "symfony/notifier": "^5.4|^6.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^5.4|^6.0", + "symfony/property-info": "^5.4|^6.0", + "symfony/rate-limiter": "^5.4|^6.0", + "symfony/scheduler": "^6.3", + "symfony/security-bundle": "^5.4|^6.0", + "symfony/semaphore": "^5.4|^6.0", + "symfony/serializer": "^6.3", + "symfony/stopwatch": "^5.4|^6.0", + "symfony/string": "^5.4|^6.0", + "symfony/translation": "^6.2.8", + "symfony/twig-bundle": "^5.4|^6.0", + "symfony/uid": "^5.4|^6.0", + "symfony/validator": "^6.3", + "symfony/web-link": "^5.4|^6.0", + "symfony/workflow": "^5.4|^6.0", + "symfony/yaml": "^5.4|^6.0", + "twig/twig": "^2.10|^3.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/framework-bundle/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-29T10:45:15+00:00" + }, + { + "name": "symfony/http-client", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "213e564da4cbf61acc9728d97e666bcdb868c10d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/213e564da4cbf61acc9728d97e666bcdb868c10d", + "reference": "213e564da4cbf61acc9728d97e666bcdb868c10d", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-client-contracts": "^3", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.3" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "3.0" + }, + "require-dev": { + "amphp/amp": "^2.5", + "amphp/http-client": "^4.2.1", + "amphp/http-tunnel": "^1.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/stopwatch": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "keywords": [ + "http" + ], + "support": { + "source": "https://github.com/symfony/http-client/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-29T15:57:12+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v3.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "3b66325d0176b4ec826bffab57c9037d759c31fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/3b66325d0176b4ec826bffab57c9037d759c31fb", + "reference": "3b66325d0176b4ec826bffab57c9037d759c31fb", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v3.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-23T14:45:45+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "b50f5e281d722cb0f4c296f908bacc3e2b721957" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/b50f5e281d722cb0f4c296f908bacc3e2b721957", + "reference": "b50f5e281d722cb0f4c296f908bacc3e2b721957", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php83": "^1.27" + }, + "conflict": { + "symfony/cache": "<6.2" + }, + "require-dev": { + "doctrine/dbal": "^2.13.1|^3.0", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", + "symfony/mime": "^5.4|^6.0", + "symfony/rate-limiter": "^5.2|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-04T21:33:54+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "9f991a964368bee8d883e8d57ced4fe9fff04dfc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/9f991a964368bee8d883e8d57ced4fe9fff04dfc", + "reference": "9f991a964368bee8d883e8d57ced4fe9fff04dfc", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.3", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/http-foundation": "^6.3.4", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/browser-kit": "<5.4", + "symfony/cache": "<5.4", + "symfony/config": "<6.1", + "symfony/console": "<5.4", + "symfony/dependency-injection": "<6.3.4", + "symfony/doctrine-bridge": "<5.4", + "symfony/form": "<5.4", + "symfony/http-client": "<5.4", + "symfony/http-client-contracts": "<2.5", + "symfony/mailer": "<5.4", + "symfony/messenger": "<5.4", + "symfony/translation": "<5.4", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<5.4", + "symfony/validator": "<5.4", + "symfony/var-dumper": "<6.3", + "twig/twig": "<2.13" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^5.4|^6.0", + "symfony/clock": "^6.2", + "symfony/config": "^6.1", + "symfony/console": "^5.4|^6.0", + "symfony/css-selector": "^5.4|^6.0", + "symfony/dependency-injection": "^6.3.4", + "symfony/dom-crawler": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", + "symfony/http-client-contracts": "^2.5|^3", + "symfony/process": "^5.4|^6.0", + "symfony/property-access": "^5.4.5|^6.0.5", + "symfony/routing": "^5.4|^6.0", + "symfony/serializer": "^6.3", + "symfony/stopwatch": "^5.4|^6.0", + "symfony/translation": "^5.4|^6.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^5.4|^6.0", + "symfony/validator": "^6.3", + "symfony/var-exporter": "^6.2", + "twig/twig": "^2.13|^3.0.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-30T06:37:04+00:00" + }, + { + "name": "symfony/intl", + "version": "v6.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/intl.git", + "reference": "1f8cb145c869ed089a8531c51a6a4b31ed0b3c69" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/intl/zipball/1f8cb145c869ed089a8531c51a6a4b31ed0b3c69", + "reference": "1f8cb145c869ed089a8531c51a6a4b31ed0b3c69", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "symfony/filesystem": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", + "symfony/var-exporter": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Intl\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Eriksen Costa", + "email": "eriksen.costa@infranology.com.br" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides access to the localization data of the ICU library", + "homepage": "https://symfony.com", + "keywords": [ + "i18n", + "icu", + "internationalization", + "intl", + "l10n", + "localization" + ], + "support": { + "source": "https://github.com/symfony/intl/tree/v6.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-20T07:43:09+00:00" + }, + { + "name": "symfony/mailer", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "d89611a7830d51b5e118bca38e390dea92f9ea06" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/d89611a7830d51b5e118bca38e390dea92f9ea06", + "reference": "d89611a7830d51b5e118bca38e390dea92f9ea06", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.1", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/mime": "^6.2", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<5.4", + "symfony/messenger": "<6.2", + "symfony/mime": "<6.2", + "symfony/twig-bridge": "<6.2.1" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/messenger": "^6.2", + "symfony/twig-bridge": "^6.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-06T09:47:15+00:00" + }, + { + "name": "symfony/messenger", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/messenger.git", + "reference": "fb29632c2abdc52f4f10f9402f8f93ebb8938234" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/messenger/zipball/fb29632c2abdc52f4f10f9402f8f93ebb8938234", + "reference": "fb29632c2abdc52f4f10f9402f8f93ebb8938234", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^1|^2|^3", + "symfony/clock": "^6.3" + }, + "conflict": { + "symfony/console": "<6.3", + "symfony/event-dispatcher": "<5.4", + "symfony/event-dispatcher-contracts": "<2.5", + "symfony/framework-bundle": "<5.4", + "symfony/http-kernel": "<5.4", + "symfony/serializer": "<5.4" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/console": "^6.3", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/property-access": "^5.4|^6.0", + "symfony/rate-limiter": "^5.4|^6.0", + "symfony/routing": "^5.4|^6.0", + "symfony/serializer": "^5.4|^6.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^5.4|^6.0", + "symfony/validator": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Messenger\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Samuel Roze", + "email": "samuel.roze@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps applications send and receive messages to/from other applications or via message queues", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/messenger/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-29T16:11:24+00:00" + }, + { + "name": "symfony/mime", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "d5179eedf1cb2946dbd760475ebf05c251ef6a6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/d5179eedf1cb2946dbd760475ebf05c251ef6a6e", + "reference": "d5179eedf1cb2946dbd760475ebf05c251ef6a6e", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<5.4", + "symfony/serializer": "<6.2.13|>=6.3,<6.3.2" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/property-access": "^5.4|^6.0", + "symfony/property-info": "^5.4|^6.0", + "symfony/serializer": "~6.2.13|^6.3.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-29T06:59:36+00:00" + }, + { + "name": "symfony/monolog-bridge", + "version": "v6.3.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bridge.git", + "reference": "04b04b8e465e0fa84940e5609b6796a8b4e51bf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/04b04b8e465e0fa84940e5609b6796a8b4e51bf1", + "reference": "04b04b8e465e0fa84940e5609b6796a8b4e51bf1", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.25.1|^2|^3", + "php": ">=8.1", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/console": "<5.4", + "symfony/http-foundation": "<5.4", + "symfony/security-core": "<6.0" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/mailer": "^5.4|^6.0", + "symfony/messenger": "^5.4|^6.0", + "symfony/mime": "^5.4|^6.0", + "symfony/security-core": "^6.0", + "symfony/var-dumper": "^5.4|^6.0" + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Monolog\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Monolog with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/monolog-bridge/tree/v6.3.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-06-08T11:13:32+00:00" + }, + { + "name": "symfony/monolog-bundle", + "version": "v3.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bundle.git", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.22 || ^2.0 || ^3.0", + "php": ">=7.1.3", + "symfony/config": "~4.4 || ^5.0 || ^6.0", + "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0", + "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0" + }, + "require-dev": { + "symfony/console": "~4.4 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.2 || ^6.0", + "symfony/yaml": "~4.4 || ^5.0 || ^6.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MonologBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony MonologBundle", + "homepage": "https://symfony.com", + "keywords": [ + "log", + "logging" + ], + "support": { + "issues": "https://github.com/symfony/monolog-bundle/issues", + "source": "https://github.com/symfony/monolog-bundle/tree/v3.8.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-10T14:24:36+00:00" + }, + { + "name": "symfony/notifier", + "version": "v6.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/notifier.git", + "reference": "a30aee1bf767835d7948138c1629e310cee26a8b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/notifier/zipball/a30aee1bf767835d7948138c1629e310cee26a8b", + "reference": "a30aee1bf767835d7948138c1629e310cee26a8b", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^1|^2|^3" + }, + "conflict": { + "symfony/event-dispatcher": "<5.4", + "symfony/event-dispatcher-contracts": "<2.5", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<5.4" + }, + "require-dev": { + "symfony/event-dispatcher-contracts": "^2.5|^3", + "symfony/http-client-contracts": "^2.5|^3", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/messenger": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Notifier\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Sends notifications via one or more channels (email, SMS, ...)", + "homepage": "https://symfony.com", + "keywords": [ + "notification", + "notifier" + ], + "support": { + "source": "https://github.com/symfony/notifier/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-12T10:17:15+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v6.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/a10f19f5198d589d5c33333cffe98dc9820332dd", + "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-12T14:21:09+00:00" + }, + { + "name": "symfony/password-hasher", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/password-hasher.git", + "reference": "278d3a49715073879f75e372ad80b8cfeca949d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/278d3a49715073879f75e372ad80b8cfeca949d3", + "reference": "278d3a49715073879f75e372ad80b8cfeca949d3", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "conflict": { + "symfony/security-core": "<5.4" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0", + "symfony/security-core": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PasswordHasher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Robin Chalas", + "email": "robin.chalas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides password hashing utilities", + "homepage": "https://symfony.com", + "keywords": [ + "hashing", + "password" + ], + "support": { + "source": "https://github.com/symfony/password-hasher/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-25T17:05:16+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "875e90aeea2777b6f135677f618529449334a612" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612", + "reference": "875e90aeea2777b6f135677f618529449334a612", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-26T09:26:14+00:00" + }, + { + "name": "symfony/polyfill-intl-icu", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-icu.git", + "reference": "e46b4da57951a16053cd751f63f4a24292788157" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/e46b4da57951a16053cd751f63f4a24292788157", + "reference": "e46b4da57951a16053cd751f63f4a24292788157", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance and support of other locales than \"en\"" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Icu\\": "" + }, + "classmap": [ + "Resources/stubs" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's ICU-related data and classes", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "icu", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-03-21T17:27:24+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "ecaafce9f77234a6a449d29e49267ba10499116d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/ecaafce9f77234a6a449d29e49267ba10499116d", + "reference": "ecaafce9f77234a6a449d29e49267ba10499116d", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-26T09:30:37+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-26T09:26:14+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "42292d99c55abe617799667f454222c54c60e229" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", + "reference": "42292d99c55abe617799667f454222c54c60e229", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-28T09:04:16+00:00" + }, + { + "name": "symfony/polyfill-php83", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "b0f46ebbeeeda3e9d2faebdfbf4b4eae9b59fa11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/b0f46ebbeeeda3e9d2faebdfbf4b4eae9b59fa11", + "reference": "b0f46ebbeeeda3e9d2faebdfbf4b4eae9b59fa11", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-php80": "^1.14" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php83/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-08-16T06:22:46+00:00" + }, + { + "name": "symfony/process", + "version": "v6.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/0b5c29118f2e980d455d2e34a5659f4579847c54", + "reference": "0b5c29118f2e980d455d2e34a5659f4579847c54", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v6.3.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-08-07T10:39:22+00:00" + }, + { + "name": "symfony/property-access", + "version": "v6.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "2dc4f9da444b8f8ff592e95d570caad67924f1d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/2dc4f9da444b8f8ff592e95d570caad67924f1d0", + "reference": "2dc4f9da444b8f8ff592e95d570caad67924f1d0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/property-info": "^5.4|^6.0" + }, + "require-dev": { + "symfony/cache": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property-path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v6.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-13T15:26:11+00:00" + }, + { + "name": "symfony/property-info", + "version": "v6.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-info.git", + "reference": "7f3a03716112269741fe2a809f8f791a371d1fcd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-info/zipball/7f3a03716112269741fe2a809f8f791a371d1fcd", + "reference": "7f3a03716112269741fe2a809f8f791a371d1fcd", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/string": "^5.4|^6.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<5.2", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/dependency-injection": "<5.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4|^2", + "phpdocumentor/reflection-docblock": "^5.2", + "phpstan/phpdoc-parser": "^1.0", + "symfony/cache": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/serializer": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts information about PHP class' properties using metadata of popular sources", + "homepage": "https://symfony.com", + "keywords": [ + "doctrine", + "phpdoc", + "property", + "symfony", + "type", + "validator" + ], + "support": { + "source": "https://github.com/symfony/property-info/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-19T08:06:44+00:00" + }, + { + "name": "symfony/routing", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "82616e59acd3e3d9c916bba798326cb7796d7d31" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/82616e59acd3e3d9c916bba798326cb7796d7d31", + "reference": "82616e59acd3e3d9c916bba798326cb7796d7d31", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "doctrine/annotations": "<1.12", + "symfony/config": "<6.2", + "symfony/dependency-injection": "<5.4", + "symfony/yaml": "<5.4" + }, + "require-dev": { + "doctrine/annotations": "^1.12|^2", + "psr/log": "^1|^2|^3", + "symfony/config": "^6.2", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/yaml": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-20T16:05:51+00:00" + }, + { + "name": "symfony/runtime", + "version": "v6.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/runtime.git", + "reference": "d5c09493647a0c1a16e6c8da308098e840d1164f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/runtime/zipball/d5c09493647a0c1a16e6c8da308098e840d1164f", + "reference": "d5c09493647a0c1a16e6c8da308098e840d1164f", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0|^2.0", + "php": ">=8.1" + }, + "conflict": { + "symfony/dotenv": "<5.4" + }, + "require-dev": { + "composer/composer": "^1.0.2|^2.0", + "symfony/console": "^5.4.9|^6.0.9", + "symfony/dotenv": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Component\\Runtime\\Internal\\ComposerPlugin" + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Runtime\\": "", + "Symfony\\Runtime\\Symfony\\Component\\": "Internal/" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Enables decoupling PHP applications from global state", + "homepage": "https://symfony.com", + "keywords": [ + "runtime" + ], + "support": { + "source": "https://github.com/symfony/runtime/tree/v6.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-16T17:05:46+00:00" + }, + { + "name": "symfony/security-bundle", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-bundle.git", + "reference": "2df460eacceb11b9287cfafddda4d27023dd9001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/2df460eacceb11b9287cfafddda4d27023dd9001", + "reference": "2df460eacceb11b9287cfafddda4d27023dd9001", + "shasum": "" + }, + "require": { + "composer-runtime-api": ">=2.1", + "ext-xml": "*", + "php": ">=8.1", + "symfony/clock": "^6.3", + "symfony/config": "^6.1", + "symfony/dependency-injection": "^6.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/http-foundation": "^6.2", + "symfony/http-kernel": "^6.2", + "symfony/password-hasher": "^5.4|^6.0", + "symfony/security-core": "^6.2", + "symfony/security-csrf": "^5.4|^6.0", + "symfony/security-http": "^6.3.4" + }, + "conflict": { + "symfony/browser-kit": "<5.4", + "symfony/console": "<5.4", + "symfony/framework-bundle": "<6.3", + "symfony/http-client": "<5.4", + "symfony/ldap": "<5.4", + "symfony/twig-bundle": "<5.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4|^2", + "symfony/asset": "^5.4|^6.0", + "symfony/browser-kit": "^5.4|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/css-selector": "^5.4|^6.0", + "symfony/dom-crawler": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/form": "^5.4|^6.0", + "symfony/framework-bundle": "^6.3", + "symfony/http-client": "^5.4|^6.0", + "symfony/ldap": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/rate-limiter": "^5.4|^6.0", + "symfony/serializer": "^5.4|^6.0", + "symfony/translation": "^5.4|^6.0", + "symfony/twig-bridge": "^5.4|^6.0", + "symfony/twig-bundle": "^5.4|^6.0", + "symfony/validator": "^5.4|^6.0", + "symfony/yaml": "^5.4|^6.0", + "twig/twig": "^2.13|^3.0.4", + "web-token/jwt-checker": "^3.1", + "web-token/jwt-signature-algorithm-ecdsa": "^3.1", + "web-token/jwt-signature-algorithm-eddsa": "^3.1", + "web-token/jwt-signature-algorithm-hmac": "^3.1", + "web-token/jwt-signature-algorithm-none": "^3.1", + "web-token/jwt-signature-algorithm-rsa": "^3.1" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\SecurityBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-bundle/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-25T17:05:55+00:00" + }, + { + "name": "symfony/security-core", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-core.git", + "reference": "ec8f24dc1195f46483510892271d01a5202bba70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-core/zipball/ec8f24dc1195f46483510892271d01a5202bba70", + "reference": "ec8f24dc1195f46483510892271d01a5202bba70", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/event-dispatcher-contracts": "^2.5|^3", + "symfony/password-hasher": "^5.4|^6.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/event-dispatcher": "<5.4", + "symfony/http-foundation": "<5.4", + "symfony/ldap": "<5.4", + "symfony/security-guard": "<5.4", + "symfony/validator": "<5.4" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "psr/container": "^1.1|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/ldap": "^5.4|^6.0", + "symfony/string": "^5.4|^6.0", + "symfony/translation": "^5.4|^6.0", + "symfony/validator": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Core\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - Core Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-core/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-10T17:47:23+00:00" + }, + { + "name": "symfony/security-csrf", + "version": "v6.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-csrf.git", + "reference": "63d7b098c448cbddb46ea5eda33b68c1ece6eb5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/63d7b098c448cbddb46ea5eda33b68c1ece6eb5b", + "reference": "63d7b098c448cbddb46ea5eda33b68c1ece6eb5b", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/security-core": "^5.4|^6.0" + }, + "conflict": { + "symfony/http-foundation": "<5.4" + }, + "require-dev": { + "symfony/http-foundation": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Csrf\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - CSRF Library", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-csrf/tree/v6.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-05T08:41:27+00:00" + }, + { + "name": "symfony/security-http", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-http.git", + "reference": "47058ea557a4c64ba86e9249651222842bd52e2a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-http/zipball/47058ea557a4c64ba86e9249651222842bd52e2a", + "reference": "47058ea557a4c64ba86e9249651222842bd52e2a", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/http-kernel": "^6.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/property-access": "^5.4|^6.0", + "symfony/security-core": "^6.3" + }, + "conflict": { + "symfony/clock": "<6.3", + "symfony/event-dispatcher": "<5.4.9|>=6,<6.0.9", + "symfony/http-client-contracts": "<3.0", + "symfony/security-bundle": "<5.4", + "symfony/security-csrf": "<5.4" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/cache": "^5.4|^6.0", + "symfony/clock": "^6.3", + "symfony/expression-language": "^5.4|^6.0", + "symfony/http-client-contracts": "^3.0", + "symfony/rate-limiter": "^5.4|^6.0", + "symfony/routing": "^5.4|^6.0", + "symfony/security-csrf": "^5.4|^6.0", + "symfony/translation": "^5.4|^6.0", + "web-token/jwt-checker": "^3.1", + "web-token/jwt-signature-algorithm-ecdsa": "^3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Security\\Http\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Security Component - HTTP Integration", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/security-http/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-08-30T06:30:46+00:00" + }, + { + "name": "symfony/serializer", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/serializer.git", + "reference": "855fc058c8bdbb69f53834f2fdb3876c9bc0ab7c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/serializer/zipball/855fc058c8bdbb69f53834f2fdb3876c9bc0ab7c", + "reference": "855fc058c8bdbb69f53834f2fdb3876c9bc0ab7c", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "doctrine/annotations": "<1.12", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/dependency-injection": "<5.4", + "symfony/property-access": "<5.4", + "symfony/property-info": "<5.4.24|>=6,<6.2.11", + "symfony/uid": "<5.4", + "symfony/yaml": "<5.4" + }, + "require-dev": { + "doctrine/annotations": "^1.12|^2", + "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", + "symfony/cache": "^5.4|^6.0", + "symfony/config": "^5.4|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/error-handler": "^5.4|^6.0", + "symfony/filesystem": "^5.4|^6.0", + "symfony/form": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/mime": "^5.4|^6.0", + "symfony/property-access": "^5.4|^6.0", + "symfony/property-info": "^5.4.24|^6.2.11", + "symfony/uid": "^5.4|^6.0", + "symfony/validator": "^5.4|^6.0", + "symfony/var-dumper": "^5.4|^6.0", + "symfony/var-exporter": "^5.4|^6.0", + "symfony/yaml": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Serializer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/serializer/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-29T16:18:53+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", + "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^2.0" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-23T14:45:45+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v6.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2", + "reference": "fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/service-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-02-16T10:14:28+00:00" + }, + { + "name": "symfony/string", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/13d76d0fb049051ed12a04bef4f9de8715bea339", + "reference": "13d76d0fb049051ed12a04bef4f9de8715bea339", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/error-handler": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/intl": "^6.2", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-18T10:38:32+00:00" + }, + { + "name": "symfony/translation", + "version": "v6.3.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "3ed078c54bc98bbe4414e1e9b2d5e85ed5a5c8bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/3ed078c54bc98bbe4414e1e9b2d5e85ed5a5c8bd", + "reference": "3ed078c54bc98bbe4414e1e9b2d5e85ed5a5c8bd", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2.5|^3.0" + }, + "conflict": { + "symfony/config": "<5.4", + "symfony/console": "<5.4", + "symfony/dependency-injection": "<5.4", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<5.4", + "symfony/service-contracts": "<2.5", + "symfony/twig-bundle": "<5.4", + "symfony/yaml": "<5.4" + }, + "provide": { + "symfony/translation-implementation": "2.3|3.0" + }, + "require-dev": { + "nikic/php-parser": "^4.13", + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", + "symfony/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/intl": "^5.4|^6.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^5.4|^6.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/v6.3.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-31T07:08:24+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "02c24deb352fb0d79db5486c0c79905a85e37e86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/02c24deb352fb0d79db5486c0c79905a85e37e86", + "reference": "02c24deb352fb0d79db5486c0c79905a85e37e86", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-30T17:17:10+00:00" + }, + { + "name": "symfony/twig-bridge", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/twig-bridge.git", + "reference": "18f2cbe1d46ad43c4d3bd45e5e6279172068e064" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/18f2cbe1d46ad43c4d3bd45e5e6279172068e064", + "reference": "18f2cbe1d46ad43c4d3bd45e5e6279172068e064", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/translation-contracts": "^2.5|^3", + "twig/twig": "^2.13|^3.0.4" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/console": "<5.4", + "symfony/form": "<6.3", + "symfony/http-foundation": "<5.4", + "symfony/http-kernel": "<6.2", + "symfony/mime": "<6.2", + "symfony/translation": "<5.4", + "symfony/workflow": "<5.4" + }, + "require-dev": { + "doctrine/annotations": "^1.12|^2", + "egulias/email-validator": "^2.1.10|^3|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^5.4|^6.0", + "symfony/asset-mapper": "^6.3", + "symfony/console": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", + "symfony/form": "^6.3", + "symfony/html-sanitizer": "^6.1", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/http-kernel": "^6.2", + "symfony/intl": "^5.4|^6.0", + "symfony/mime": "^6.2", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/property-info": "^5.4|^6.0", + "symfony/routing": "^5.4|^6.0", + "symfony/security-acl": "^2.8|^3.0", + "symfony/security-core": "^5.4|^6.0", + "symfony/security-csrf": "^5.4|^6.0", + "symfony/security-http": "^5.4|^6.0", + "symfony/serializer": "^6.2", + "symfony/stopwatch": "^5.4|^6.0", + "symfony/translation": "^6.1", + "symfony/web-link": "^5.4|^6.0", + "symfony/workflow": "^5.4|^6.0", + "symfony/yaml": "^5.4|^6.0", + "twig/cssinliner-extra": "^2.12|^3", + "twig/inky-extra": "^2.12|^3", + "twig/markdown-extra": "^2.12|^3" + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Twig\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Twig with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/twig-bridge/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-12T06:57:20+00:00" + }, + { + "name": "symfony/twig-bundle", + "version": "v6.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/twig-bundle.git", + "reference": "d0cd4d1675c0582d27c2e8bb0dc27c0303d8e3ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/d0cd4d1675c0582d27c2e8bb0dc27c0303d8e3ea", + "reference": "d0cd4d1675c0582d27c2e8bb0dc27c0303d8e3ea", + "shasum": "" + }, + "require": { + "composer-runtime-api": ">=2.1", + "php": ">=8.1", + "symfony/config": "^6.1", + "symfony/dependency-injection": "^6.1", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/http-kernel": "^6.2", + "symfony/twig-bridge": "^6.3", + "twig/twig": "^2.13|^3.0.4" + }, + "conflict": { + "symfony/framework-bundle": "<5.4", + "symfony/translation": "<5.4" + }, + "require-dev": { + "doctrine/annotations": "^1.10.4|^2", + "symfony/asset": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", + "symfony/form": "^5.4|^6.0", + "symfony/framework-bundle": "^5.4|^6.0", + "symfony/routing": "^5.4|^6.0", + "symfony/stopwatch": "^5.4|^6.0", + "symfony/translation": "^5.4|^6.0", + "symfony/web-link": "^5.4|^6.0", + "symfony/yaml": "^5.4|^6.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\TwigBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of Twig into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/twig-bundle/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-06T09:53:41+00:00" + }, + { + "name": "symfony/validator", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/validator.git", + "reference": "48e815ba3b5eb72e632588dbf7ea2dc4e608ee47" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/validator/zipball/48e815ba3b5eb72e632588dbf7ea2dc4e608ee47", + "reference": "48e815ba3b5eb72e632588dbf7ea2dc4e608ee47", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php83": "^1.27", + "symfony/translation-contracts": "^2.5|^3" + }, + "conflict": { + "doctrine/annotations": "<1.13", + "doctrine/lexer": "<1.1", + "symfony/dependency-injection": "<5.4", + "symfony/expression-language": "<5.4", + "symfony/http-kernel": "<5.4", + "symfony/intl": "<5.4", + "symfony/property-info": "<5.4", + "symfony/translation": "<5.4", + "symfony/yaml": "<5.4" + }, + "require-dev": { + "doctrine/annotations": "^1.13|^2", + "egulias/email-validator": "^2.1.10|^3|^4", + "symfony/cache": "^5.4|^6.0", + "symfony/config": "^5.4|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/expression-language": "^5.4|^6.0", + "symfony/finder": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/http-foundation": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/intl": "^5.4|^6.0", + "symfony/mime": "^5.4|^6.0", + "symfony/property-access": "^5.4|^6.0", + "symfony/property-info": "^5.4|^6.0", + "symfony/translation": "^5.4|^6.0", + "symfony/yaml": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Validator\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to validate values", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/validator/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-29T07:41:15+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v6.3.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "3d9999376be5fea8de47752837a3e1d1c5f69ef5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3d9999376be5fea8de47752837a3e1d1c5f69ef5", + "reference": "3d9999376be5fea8de47752837a3e1d1c5f69ef5", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<5.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/uid": "^5.4|^6.0", + "twig/twig": "^2.13|^3.0.4" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v6.3.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-12T10:11:35+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v6.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "df1f8aac5751871b83d30bf3e2c355770f8f0691" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/df1f8aac5751871b83d30bf3e2c355770f8f0691", + "reference": "df1f8aac5751871b83d30bf3e2c355770f8f0691", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "symfony/var-dumper": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v6.3.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-08-16T18:14:47+00:00" + }, + { + "name": "symfony/web-link", + "version": "v6.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/web-link.git", + "reference": "0989ca617d0703cdca501a245f10e194ff22315b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/web-link/zipball/0989ca617d0703cdca501a245f10e194ff22315b", + "reference": "0989ca617d0703cdca501a245f10e194ff22315b", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/link": "^1.1|^2.0" + }, + "conflict": { + "symfony/http-kernel": "<5.4" + }, + "provide": { + "psr/link-implementation": "1.0|2.0" + }, + "require-dev": { + "symfony/http-kernel": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\WebLink\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Manages links between resources", + "homepage": "https://symfony.com", + "keywords": [ + "dns-prefetch", + "http", + "http2", + "link", + "performance", + "prefetch", + "preload", + "prerender", + "psr13", + "push" + ], + "support": { + "source": "https://github.com/symfony/web-link/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-04-21T14:41:17+00:00" + }, + { + "name": "symfony/yaml", + "version": "v6.3.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "e23292e8c07c85b971b44c1c4b87af52133e2add" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/e23292e8c07c85b971b44c1c4b87af52133e2add", + "reference": "e23292e8c07c85b971b44c1c4b87af52133e2add", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<5.4" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v6.3.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-31T07:08:24+00:00" + }, + { + "name": "twig/extra-bundle", + "version": "v3.7.1", + "source": { + "type": "git", + "url": "https://github.com/twigphp/twig-extra-bundle.git", + "reference": "f10baafe6eb0ecd615d52d5cbfb713a39f68e8f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/f10baafe6eb0ecd615d52d5cbfb713a39f68e8f3", + "reference": "f10baafe6eb0ecd615d52d5cbfb713a39f68e8f3", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/framework-bundle": "^5.4|^6.0", + "symfony/twig-bundle": "^5.4|^6.0", + "twig/twig": "^2.7|^3.0" + }, + "require-dev": { + "league/commonmark": "^1.0|^2.0", + "symfony/phpunit-bridge": "^5.4|^6.3", + "twig/cache-extra": "^3.0", + "twig/cssinliner-extra": "^2.12|^3.0", + "twig/html-extra": "^2.12|^3.0", + "twig/inky-extra": "^2.12|^3.0", + "twig/intl-extra": "^2.12|^3.0", + "twig/markdown-extra": "^2.12|^3.0", + "twig/string-extra": "^2.12|^3.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Twig\\Extra\\TwigExtraBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "A Symfony bundle for extra Twig extensions", + "homepage": "https://twig.symfony.com", + "keywords": [ + "bundle", + "extra", + "twig" + ], + "support": { + "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.7.1" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2023-07-29T15:34:56+00:00" + }, + { + "name": "twig/twig", + "version": "v3.7.1", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", + "reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "psr/container": "^1.0|^2.0", + "symfony/phpunit-bridge": "^5.4.9|^6.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v3.7.1" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2023-08-28T11:09:02+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "packages-dev": [ + { + "name": "masterminds/html5", + "version": "2.8.1", + "source": { + "type": "git", + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f47dcf3c70c584de14f21143c55d9939631bc6cf", + "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.8.1" + }, + "time": "2023-05-10T11:58:31+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2023-03-08T13:26:56+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.17.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + }, + "time": "2023-08-13T19:53:39+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.29", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.15", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-09-19T04:57:46+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.13", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.28", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2023-09-19T05:39:22+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-05-07T05:35:17+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T06:03:37+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bde739e7565280bda77be70044ac1047bc007e34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-08-02T09:26:13+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v6.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "ca4a988488f61ac18f8f845445eabdd36f89aa8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/ca4a988488f61ac18f8f845445eabdd36f89aa8d", + "reference": "ca4a988488f61ac18f8f845445eabdd36f89aa8d", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/dom-crawler": "^5.4|^6.0" + }, + "require-dev": { + "symfony/css-selector": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/mime": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/browser-kit/tree/v6.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-06T06:56:43+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v6.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "883d961421ab1709877c10ac99451632a3d6fa57" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/883d961421ab1709877c10ac99451632a3d6fa57", + "reference": "883d961421ab1709877c10ac99451632a3d6fa57", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v6.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-12T16:00:22+00:00" + }, + { + "name": "symfony/debug-bundle", + "version": "v6.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug-bundle.git", + "reference": "3f04a578e1a9f1d7da84a87b690c03123e5d8c31" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/3f04a578e1a9f1d7da84a87b690c03123e5d8c31", + "reference": "3f04a578e1a9f1d7da84a87b690c03123e5d8c31", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=8.1", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/twig-bridge": "^5.4|^6.0", + "symfony/var-dumper": "^5.4|^6.0" + }, + "conflict": { + "symfony/config": "<5.4", + "symfony/dependency-injection": "<5.4" + }, + "require-dev": { + "symfony/config": "^5.4|^6.0", + "symfony/web-profiler-bundle": "^5.4|^6.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\DebugBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of the Symfony VarDumper component and the ServerLogCommand from MonologBridge into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/debug-bundle/tree/v6.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-13T14:29:38+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v6.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "3fdd2a3d5fdc363b2e8dbf817f9726a4d013cbd1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/3fdd2a3d5fdc363b2e8dbf817f9726a4d013cbd1", + "reference": "3fdd2a3d5fdc363b2e8dbf817f9726a4d013cbd1", + "shasum": "" + }, + "require": { + "masterminds/html5": "^2.6", + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "symfony/css-selector": "^5.4|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v6.3.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-08-01T07:43:40+00:00" + }, + { + "name": "symfony/maker-bundle", + "version": "v1.51.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/maker-bundle.git", + "reference": "0890fd3cf1e2a5221f9b3c6ee1769c537aef683d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/0890fd3cf1e2a5221f9b3c6ee1769c537aef683d", + "reference": "0890fd3cf1e2a5221f9b3c6ee1769c537aef683d", + "shasum": "" + }, + "require": { + "doctrine/inflector": "^2.0", + "nikic/php-parser": "^4.11", + "php": ">=8.1", + "symfony/config": "^6.3|^7.0", + "symfony/console": "^6.3|^7.0", + "symfony/dependency-injection": "^6.3|^7.0", + "symfony/deprecation-contracts": "^2.2|^3", + "symfony/filesystem": "^6.3|^7.0", + "symfony/finder": "^6.3|^7.0", + "symfony/framework-bundle": "^6.3|^7.0", + "symfony/http-kernel": "^6.3|^7.0", + "symfony/process": "^6.3|^7.0" + }, + "conflict": { + "doctrine/doctrine-bundle": "<2.4", + "doctrine/orm": "<2.10" + }, + "require-dev": { + "composer/semver": "^3.0", + "doctrine/doctrine-bundle": "^2.5.0", + "doctrine/orm": "^2.10.0", + "symfony/http-client": "^6.3|^7.0", + "symfony/phpunit-bridge": "^6.3|^7.0", + "symfony/security-core": "^6.3|^7.0", + "symfony/yaml": "^6.3|^7.0", + "twig/twig": "^2.0|^3.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MakerBundle\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Maker helps you create empty commands, controllers, form classes, tests and more so you can forget about writing boilerplate code.", + "homepage": "https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html", + "keywords": [ + "code generator", + "dev", + "generator", + "scaffold", + "scaffolding" + ], + "support": { + "issues": "https://github.com/symfony/maker-bundle/issues", + "source": "https://github.com/symfony/maker-bundle/tree/v1.51.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-09-18T18:17:31+00:00" + }, + { + "name": "symfony/phpunit-bridge", + "version": "v6.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/phpunit-bridge.git", + "reference": "e020e1efbd1b42cb670fcd7d19a25abbddba035d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/e020e1efbd1b42cb670fcd7d19a25abbddba035d", + "reference": "e020e1efbd1b42cb670fcd7d19a25abbddba035d", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "conflict": { + "phpunit/phpunit": "<7.5|9.1.2" + }, + "require-dev": { + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/error-handler": "^5.4|^6.0", + "symfony/polyfill-php81": "^1.27" + }, + "bin": [ + "bin/simple-phpunit" + ], + "type": "symfony-bridge", + "extra": { + "thanks": { + "name": "phpunit/phpunit", + "url": "https://github.com/sebastianbergmann/phpunit" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Bridge\\PhpUnit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides utilities for PHPUnit, especially user deprecation notices management", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/phpunit-bridge/tree/v6.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-12T16:00:22+00:00" + }, + { + "name": "symfony/web-profiler-bundle", + "version": "v6.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/web-profiler-bundle.git", + "reference": "6101b5ab7857c373d237e121f9060c68b32e1373" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/6101b5ab7857c373d237e121f9060c68b32e1373", + "reference": "6101b5ab7857c373d237e121f9060c68b32e1373", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/config": "^5.4|^6.0", + "symfony/framework-bundle": "^5.4|^6.0", + "symfony/http-kernel": "^6.3", + "symfony/routing": "^5.4|^6.0", + "symfony/twig-bundle": "^5.4|^6.0", + "twig/twig": "^2.13|^3.0.4" + }, + "conflict": { + "symfony/form": "<5.4", + "symfony/mailer": "<5.4", + "symfony/messenger": "<5.4" + }, + "require-dev": { + "symfony/browser-kit": "^5.4|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/css-selector": "^5.4|^6.0", + "symfony/stopwatch": "^5.4|^6.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\WebProfilerBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a development tool that gives detailed information about the execution of any request", + "homepage": "https://symfony.com", + "keywords": [ + "dev" + ], + "support": { + "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-19T20:17:28+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": ">=8.1", + "ext-ctype": "*", + "ext-iconv": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/config/bundles.php b/config/bundles.php new file mode 100644 index 0000000..0457f99 --- /dev/null +++ b/config/bundles.php @@ -0,0 +1,14 @@ + ['all' => true], + Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], + Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], + Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true], + Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], + Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], + Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true], + Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], + Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], + Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], +]; diff --git a/config/packages/cache.yaml b/config/packages/cache.yaml new file mode 100644 index 0000000..6899b72 --- /dev/null +++ b/config/packages/cache.yaml @@ -0,0 +1,19 @@ +framework: + cache: + # Unique name of your app: used to compute stable namespaces for cache keys. + #prefix_seed: your_vendor_name/app_name + + # The "app" cache stores to the filesystem by default. + # The data in this cache should persist between deploys. + # Other options include: + + # Redis + #app: cache.adapter.redis + #default_redis_provider: redis://localhost + + # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) + #app: cache.adapter.apcu + + # Namespaced pools use the above "app" backend by default + #pools: + #my.dedicated.cache: null diff --git a/config/packages/debug.yaml b/config/packages/debug.yaml new file mode 100644 index 0000000..ad874af --- /dev/null +++ b/config/packages/debug.yaml @@ -0,0 +1,5 @@ +when@dev: + debug: + # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser. + # See the "server:dump" command to start a new server. + dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%" diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml new file mode 100644 index 0000000..ec0f77e --- /dev/null +++ b/config/packages/doctrine.yaml @@ -0,0 +1,48 @@ +doctrine: + dbal: + url: '%env(resolve:DATABASE_URL)%' + + # IMPORTANT: You MUST configure your server version, + # either here or in the DATABASE_URL env var (see .env file) + #server_version: '15' + + profiling_collect_backtrace: '%kernel.debug%' + orm: + auto_generate_proxy_classes: true + enable_lazy_ghost_objects: true + report_fields_where_declared: true + validate_xml_mapping: true + naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware + auto_mapping: true + mappings: + App: + is_bundle: false + dir: '%kernel.project_dir%/src/Entity' + prefix: 'App\Entity' + alias: App + +when@test: + doctrine: + dbal: + # "TEST_TOKEN" is typically set by ParaTest + dbname_suffix: '_test%env(default::TEST_TOKEN)%' + +when@prod: + doctrine: + orm: + auto_generate_proxy_classes: false + proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies' + query_cache_driver: + type: pool + pool: doctrine.system_cache_pool + result_cache_driver: + type: pool + pool: doctrine.result_cache_pool + + framework: + cache: + pools: + doctrine.result_cache_pool: + adapter: cache.app + doctrine.system_cache_pool: + adapter: cache.system diff --git a/config/packages/doctrine_migrations.yaml b/config/packages/doctrine_migrations.yaml new file mode 100644 index 0000000..29231d9 --- /dev/null +++ b/config/packages/doctrine_migrations.yaml @@ -0,0 +1,6 @@ +doctrine_migrations: + migrations_paths: + # namespace is arbitrary but should be different from App\Migrations + # as migrations classes should NOT be autoloaded + 'DoctrineMigrations': '%kernel.project_dir%/migrations' + enable_profiler: false diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml new file mode 100644 index 0000000..6d85c29 --- /dev/null +++ b/config/packages/framework.yaml @@ -0,0 +1,25 @@ +# see https://symfony.com/doc/current/reference/configuration/framework.html +framework: + secret: '%env(APP_SECRET)%' + #csrf_protection: true + http_method_override: false + handle_all_throwables: true + + # Enables session support. Note that the session will ONLY be started if you read or write from it. + # Remove or comment this section to explicitly disable session support. + session: + handler_id: null + cookie_secure: auto + cookie_samesite: lax + storage_factory_id: session.storage.factory.native + + #esi: true + #fragments: true + php_errors: + log: true + +when@test: + framework: + test: true + session: + storage_factory_id: session.storage.factory.mock_file diff --git a/config/packages/mailer.yaml b/config/packages/mailer.yaml new file mode 100644 index 0000000..56a650d --- /dev/null +++ b/config/packages/mailer.yaml @@ -0,0 +1,3 @@ +framework: + mailer: + dsn: '%env(MAILER_DSN)%' diff --git a/config/packages/messenger.yaml b/config/packages/messenger.yaml new file mode 100644 index 0000000..587083a --- /dev/null +++ b/config/packages/messenger.yaml @@ -0,0 +1,24 @@ +framework: + messenger: + failure_transport: failed + + transports: + # https://symfony.com/doc/current/messenger.html#transport-configuration + async: + dsn: '%env(MESSENGER_TRANSPORT_DSN)%' + options: + use_notify: true + check_delayed_interval: 60000 + retry_strategy: + max_retries: 3 + multiplier: 2 + failed: 'doctrine://default?queue_name=failed' + # sync: 'sync://' + + routing: + Symfony\Component\Mailer\Messenger\SendEmailMessage: async + Symfony\Component\Notifier\Message\ChatMessage: async + Symfony\Component\Notifier\Message\SmsMessage: async + + # Route your messages to the transports + # 'App\Message\YourMessage': async diff --git a/config/packages/monolog.yaml b/config/packages/monolog.yaml new file mode 100644 index 0000000..8c9efa9 --- /dev/null +++ b/config/packages/monolog.yaml @@ -0,0 +1,61 @@ +monolog: + channels: + - deprecation # Deprecations are logged in the dedicated "deprecation" channel when it exists + +when@dev: + monolog: + handlers: + main: + type: stream + path: "%kernel.logs_dir%/%kernel.environment%.log" + level: debug + channels: ["!event"] + # uncomment to get logging in your browser + # you may have to allow bigger header sizes in your Web server configuration + #firephp: + # type: firephp + # level: info + #chromephp: + # type: chromephp + # level: info + console: + type: console + process_psr_3_messages: false + channels: ["!event", "!doctrine", "!console"] + +when@test: + monolog: + handlers: + main: + type: fingers_crossed + action_level: error + handler: nested + excluded_http_codes: [404, 405] + channels: ["!event"] + nested: + type: stream + path: "%kernel.logs_dir%/%kernel.environment%.log" + level: debug + +when@prod: + monolog: + handlers: + main: + type: fingers_crossed + action_level: error + handler: nested + excluded_http_codes: [404, 405] + buffer_size: 50 # How many messages should be saved? Prevent memory leaks + nested: + type: stream + path: php://stderr + level: debug + formatter: monolog.formatter.json + console: + type: console + process_psr_3_messages: false + channels: ["!event", "!doctrine"] + deprecation: + type: stream + channels: [deprecation] + path: php://stderr diff --git a/config/packages/notifier.yaml b/config/packages/notifier.yaml new file mode 100644 index 0000000..7f4bed1 --- /dev/null +++ b/config/packages/notifier.yaml @@ -0,0 +1,13 @@ +framework: + notifier: + chatter_transports: + texter_transports: + crowdin: '%env(CROWDIN_DSN)%' + channel_policy: + # use chat/slack, chat/telegram, sms/twilio or sms/nexmo + urgent: ['email'] + high: ['email'] + medium: ['email'] + low: ['email'] + admin_recipients: + - { email: admin@example.com } diff --git a/config/packages/routing.yaml b/config/packages/routing.yaml new file mode 100644 index 0000000..4b766ce --- /dev/null +++ b/config/packages/routing.yaml @@ -0,0 +1,12 @@ +framework: + router: + utf8: true + + # Configure how to generate URLs in non-HTTP contexts, such as CLI commands. + # See https://symfony.com/doc/current/routing.html#generating-urls-in-commands + #default_uri: http://localhost + +when@prod: + framework: + router: + strict_requirements: null diff --git a/config/packages/security.yaml b/config/packages/security.yaml new file mode 100644 index 0000000..367af25 --- /dev/null +++ b/config/packages/security.yaml @@ -0,0 +1,39 @@ +security: + # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords + password_hashers: + Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' + # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider + providers: + users_in_memory: { memory: null } + firewalls: + dev: + pattern: ^/(_(profiler|wdt)|css|images|js)/ + security: false + main: + lazy: true + provider: users_in_memory + + # activate different ways to authenticate + # https://symfony.com/doc/current/security.html#the-firewall + + # https://symfony.com/doc/current/security/impersonating_user.html + # switch_user: true + + # Easy way to control access for large sections of your site + # Note: Only the *first* access control that matches will be used + access_control: + # - { path: ^/admin, roles: ROLE_ADMIN } + # - { path: ^/profile, roles: ROLE_USER } + +when@test: + security: + password_hashers: + # By default, password hashers are resource intensive and take time. This is + # important to generate secure password hashes. In tests however, secure hashes + # are not important, waste resources and increase test times. The following + # reduces the work factor to the lowest possible values. + Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: + algorithm: auto + cost: 4 # Lowest possible value for bcrypt + time_cost: 3 # Lowest possible value for argon + memory_cost: 10 # Lowest possible value for argon diff --git a/config/packages/translation.yaml b/config/packages/translation.yaml new file mode 100644 index 0000000..888f0ba --- /dev/null +++ b/config/packages/translation.yaml @@ -0,0 +1,15 @@ +framework: + default_locale: en + translator: + default_path: '%kernel.project_dir%/translations' + fallbacks: + - en +# providers: +# crowdin: +# dsn: '%env(CROWDIN_DSN)%' +# loco: +# dsn: '%env(LOCO_DSN)%' +# lokalise: +# dsn: '%env(LOKALISE_DSN)%' +# phrase: +# dsn: '%env(PHRASE_DSN)%' diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml new file mode 100644 index 0000000..8052606 --- /dev/null +++ b/config/packages/twig.yaml @@ -0,0 +1,9 @@ +twig: + default_path: '%kernel.project_dir%/templates' + globals: + version: '%app.version%' + name: '%app.name%' + +when@test: + twig: + strict_variables: true diff --git a/config/packages/validator.yaml b/config/packages/validator.yaml new file mode 100644 index 0000000..0201281 --- /dev/null +++ b/config/packages/validator.yaml @@ -0,0 +1,13 @@ +framework: + validation: + email_validation_mode: html5 + + # Enables validator auto-mapping support. + # For instance, basic validation constraints will be inferred from Doctrine's metadata. + #auto_mapping: + # App\Entity\: [] + +when@test: + framework: + validation: + not_compromised_password: false diff --git a/config/packages/web_profiler.yaml b/config/packages/web_profiler.yaml new file mode 100644 index 0000000..b946111 --- /dev/null +++ b/config/packages/web_profiler.yaml @@ -0,0 +1,17 @@ +when@dev: + web_profiler: + toolbar: true + intercept_redirects: false + + framework: + profiler: + only_exceptions: false + collect_serializer_data: true + +when@test: + web_profiler: + toolbar: false + intercept_redirects: false + + framework: + profiler: { collect: false } diff --git a/config/preload.php b/config/preload.php new file mode 100644 index 0000000..5ebcdb2 --- /dev/null +++ b/config/preload.php @@ -0,0 +1,5 @@ +%6!)OTp)F9XxChtZ?(R}(Deh7rxEI&r#kDxaT?!Pqq33tr zbH4Ar_m9gMc>+)NCOa8>&9&B?b1A<=K*R?;|L9r@YpTt7(WAhAe|{js9<~l(8(w}s zPHujH^4|mD0YHGfr?4i$&}}^87XScb9SeXBJJ8et>}qFb@4{~9Zo=+iXM5D9>%1)V ziQ!JHqkH{AnFo)~0e~nz@#Dx@ufaVwZ|EocJLu1c0sx%ySVMB@_h^ob1FSCv16 zK>&}@4=XA!3p1jr*$?h#yIcM&J>75K?Jo$_>Wva!`1{8h=KOj(DSNth(1C8(4sYMl z>atdD->qhU{DU=qDQO2C_3^EK^aMXX+}>wfJpCD{ebQp>C^Cn(i+FcT?Cjq{Iq!nR z{I6ECMDH6N&aJ^&DTcZQPiE71x3x1~%_;{Uo4<{{{^Q58-M6$)GoC$q+41_9USEu| zr(|R|BQcpXt-P&LGBvJRP)fw4u*!b4ilJuu0qnZ`dO_V*pXir<36OQoY&aEd%|!3} zx`pMEVbSG>mfo|N6*o{Y2nDBN-~bqBXLX>)Kyop2Ue7U30s8R^i(ytQr^LMbP_ za24ZY#4_Bxo&9}w+*7%i1MedA{c?SQjU)M_`K2J=) z`k)-)ZTAZ+E=Q}CDiMLpKDW(_qW(*X%YID{wpV|?y9z_fsfJes=Zemn&A-Su^>5hI z^MilvMIU6BJvm=(DEe8SgKv${wKuu8{O54C|6Ge}NS?^mJ?U}o=jt3AY*IxJuUcsC zI1Kmg>=<;d_|`eMTMu+g2UKTl^Ek7WsgyT#Y^7P<+{S9`YAip%bIo`J0^j0&1$y$v zq?Jxs1(g1-n=iMxKpC!CzTN#%GaWaO0NL~eCClc^OWI;z`13bYHc|9{y{rEYs==;x zYg%Y~(G#EsU&yb@ ziFJ-A_OCYd07gK-tiYH9a$lE@RPFeq?aC3L)3GI&^<+ z4>h-Lcw}m1NDdeO_?api25bk&P1X7n&-b(N5`ME#%B9x-X|iRs{Lu#N?X_# zp&F`K{B}qs5BV z*Hn)l*LS10dsI~L)JuDM=~RtX9S^r|*QEo8uSJRGoU-!!O>U>YXl&t%wCm}iJ#ux_ zXrn}bSrW|(G%7O(4+Vsu8+`fZD3rx*%z$gqGGGOFGVt)zkx>++nx3vFJ4H7m^k%r- zU|EQhT@t53{|k~sSvC*H`Q?kdceqI6Pjc4QMGAn4%8=t_m5F|Le4)Nb`DDMJKAu}M z+q4!R459j&r$Rdn)64uaM`5*pdVQ6bJ)nZ?IB)4b@IW6l?Uvw{4Q41NpN!+Y*x0m~ zdFI;btk#5UL+f=425H7NxGN2Agb~3=d~9q=cezBsT^G;Ob6xoB8|`Y2Wo+)J$_@jz z>ABj4Cq6OT+Jv(K{-7~e`c?C?g;{0CfnO)h_J5c@mzm78gl?Z+`nJ{-mhEm9Pu*0$ zekd-pINo$}V|$2r@7e#YzxvDg<9N{?;nGb1(g&`)_}ICXK%KOV?(MKIXPwHFy<6TM zep_Ep&qp}OVk;DbU(SUg5l!29EbW_{*g+lGok-UlLryHqN8>PD8yk8s><-uAoTTXF z1~JN-&0~L&HW@!HPpsO_@d#Yr_`nGu+V6H@ynp@8_oi5YN4l*ghv5ybd)`(cJ!Trc z+wOsn2{Bem`Ns&G+s&zs`=P5Pb5AR!U(F_Z_wv6*UKgy|Adc)%a&V3lj2&<{jHq?2*GeuX%r`Ba!)TiBWHJx?PapjfqOG2R`t%`PzPgnHcAJP177T1eH=4homry`sDf4>u)a%i{R z5xd(|>K~E{7{FyETJ>KoN*4C>um5!LAs0@JckNG*u&!j*QxSmPYuo>Add^E?g3aBUnN5EOYpX7>i!OL zaxi0{3#toTUfSFGxgQ~+GePX^;Mz;W2Am8E`{GT;e$h~0PE8i|!}TW{H%>g5`MqUa zttfzXYo!5DB`xU~t+KO{gwKaGzq%}eeH%z^jIPWn*X7`(ow3|*tUQij+CLT#yn~39 zBoDynI7m(mSi(;T$Sx&OFpUaPF5w2+36dCr6Nn6@G)K8kfe_>kde!%I0H z#k4Y=!gR8VL87UT3Y`WzqrmQ0WlfWi=3xH7SHWWxb%J{d!ocQWWz7wcDsnW`S}u!w zcle3XKog!Mms?^6H9CP@PCqikJzpU{fy{)|n9z8^0~$znJ&s}Lvk|-##?MI6L<8xW zZCd|@Rs8hl5A>!RSFESWEX-qh1QMNtp1KZ7&Fu>dMZ;B=ptVGb>~5@3EurQ*Lc{et zmMo!$BcRU-LR3#E>7brbmN3~Tpr`$ehRb|Z5`^d_JMj+pMo$8MU#{twliLST+D{}j zAr8Ni6xy6yW#7i-d4+Vo$yl!$Aqm{anF7j=aiew(f=5mzA|yGv5$UjMyn1hoAy;&^ zrh*2&3llM8Q-f6L77p7PyAcl6NA!J{%uIXvXHN`m+u z%P;2FWwCrBO^0*pa(l$JhQrMo|ARqRe=*4W9}Gg7{jkyp$0r!q)HewPZGb=~?paEM z5uq{j#eY^90%PW_EPC&nv1#ZCxlR5q2ONq#gAtitvbGyFTp|1A#a?2vtX^XgqECo| z)nd2I`euDa+8Od}y*Q?Qq*-ay9~>6Pqh=CwGk{)_bPO~sZt$qWw>!g#rhRc7#>HAq zh&3iOB$hea)zLTWwP3PAmv2?IxfJ>q->vi1WQKMq5$`q>;av!#ayWhxO9&W(cB4^p zgcT+*Q0fPes?c9V5hDj=Vs|$IVN)@M{FlB;HNe8_=t4N5>=Fs3WMTx12;dpKP<-SCi# z=8W{bc}>9PjLvk(DW6Q#M9J;~%5NbO9|EB5oXSR7r%@|>J0_Z8Wz2UhKj7w!#$?C@ zfny(DkbEE%ZNimyH!bK&NXbR9%L~bc0>1@nF}HKkP-73cuMez3HD=|H?4o_e$-f>@ zJ=HlM5{M-HHbxPoRTWSj+%x~WhLtJ=HMsgycUXA!#Axx9y_n2(Ekpjnj@nBzz7wqF z4+2yqAEnQFtH~wUyhs+^1*p=Kn@(4J8cwn#1+uNLWpXBc<)%jmh#IW<%?UAz)8j`> zr4#rmTTohV$=Qp%K4bdgus;lIdofk^afs_OSmbuW+r6V`Ip<;1UKXCvDd?|Ukx4jr^)hA!CfR43R+B!qy8O77H6UQ>!?6UE9sgRHeRuU!yd zJDnmYt7WRkxb(tah?KGvos=d%M*b61(Nw=Ph6t`t;!lyuodWOkLFxgit}_6SP0|3u z2rFmpb-H%;>x{>Xi`JhoLM2C}JHDkt>tmXMDfPrX++dMIBaw(-WVqwA%4_nf-GF+nZae(otbx#y$_d zWF1tJI~r#fNY)RO;~G}jWSIFaq3CkRT#+g{LZ%)_TVg)?&bL(kc=EK2Yup8 zrxhN_L!4g+&F3CLG4zdpZ%0|Cvn?`87MXg9%0cdY*0lEax_AKm?P)km z(!dmm?X_1xgoh)y=|0J?208# z?@DY(hUhyFs%^7G#u)MtTUC_I^XV5yz;ofc)+EV{C4EoIdvpD1IVP>?rG-hk-qzb~ zTZ4&Tw?1drmB&sE7OT#z7J`J@qXT%xZZp7<{mTbZEn?X_jW<*gz*BEo!=@jDCEOECjhjjBC^^p)VqkIzLoYWj$wQ0; zrvOj%hSz~dA&HLRGr^O-+ET$k(6WLTShU9zi{&5=P)&AR4*5jw(wik_G z9o0Y%s6;p)P&v%`tT(kFJ#2y1A? zn`Ftnl0|Yn%9kS!Lp$hVDYqG6QrBw41(l;6+;)G7RM#3%HWn2Ry>f9A44^&0BI#Kj zmr}>EVV^pi9Sd`FS(&B(&N&+IwVaA3q5Bao*uDthG5~BrbOh)FRwRP#K_#NE0#ZP8 z{i*PsN~lJWh-GdW0G6(=NC6ZKondw616F;Kn^kdS;a15dKlm`q^aw{C9AsBP3Uc%Z zt=W;WJteVz3_?+$OP*45L$8s?#A}|j(2AB=s~pF9$7`P3d(ZUP9^1mk8Bn>CK01*l z9s_qws4bl3%RMqnJ94=rK!pOpvTOk*hXQw^$O9yvZkb2F2@GgZ%fZ;BKTDvhb4-=x zCY9LaBr5|$LXmi5`?XxYrXAFs=}8#}KE8PITUgGEoptTRFrXV=S6y>}* z%z}49>M)>y>WaA>sVuH1@IM0ueRRK8#@95PwFK~1!lPeDmS9200Xm2tGKlItSR_`? zTq7@wYm^AKNE91W)ufCpk#NLKRN=#%$|#`QN{krbCS(p8lV6KI%#vHoxHKRO|1f~i z^IsqV`_xQ_%u2LX#r?+buckn(s;C>0gt28TSJnc3s3hQ?Z71k6&h%FKn^>xa+0Ij# z{euY;phJ+}QFVei#()HdC|S6KF3|GD`X}TpRm&G#M-AA1<=Bgo;?J9Kb~O9WU+C*X zQ@wP7`!!rz%VxU3Ae2eMjgwy!gx!5;HCcU~b~GSKCgfFMCMzmLNkTh|!DORw+2IVq{@aMbGY z$1PrUoGnNDKRWnG-^xGqz*paA- zso0U8Q5bca(ni1L_ z2rr6|pDE08olEuwSqu#Y%A_Omr??BVYP3n56{WaMqzsIT z!03&2XLlGv%djjY)$}q%SMt@EW5I@L45fExA;(j;$19~IG}g`3_$V?`{5W^_K@7Y? z)vQEd(>gI(?Em?tL^>f{J#_&_*EmBiO2r)C9%h>g1zf*wwkcipy^OyM^+1|1n5i z>ebk^nj`J!*ubsCf(`uj%!G(dQsSi#q;aN943R2wiD6(!0)zQc@w)u?RIbDT-i$qI zG_r2I2z*N8f+`wEL@Q827*7>%Mg|$mo1W^An;y63QXDNxJ#XH8^6PyA!V?dNWo#2kBAB4f@n&-bSz5{&)ZQT z9jL5%j5^3U1Sf-ktXDz~vY6o#u@(YU8ax(^I?N)Mx~(37+?_u~THF-q^oHaln%zu5 zzO_o(r=}@j_Y*^UaGa#b41eb|=Z?NXu?H?=*LcU#w1yV}pBo7p(;IQO_csfo$YqE% z-bI-!o4?pY4k-tZ1D}`D4(d_rR*U@w(P=X<#Fc(QRA!pV^roqQ$t`6iAMdSpMj{@m zG0*KGW!yAVjdu+Fn`G)4j}Nd@n&1ZY3b6x3`T?d;64-kH&O2+o`G>V5wkTP+;xrxj zxAG2_v(RPaUnt!NX$&4&!Rc%w+W+@uxB_>QzbPipeEfnj>z;$k5;gEsLWnc@ z8xVXn7_0tr`w8!THx2STnHZ)bMluWmh3@B|qWPYT%LM*+t>14YYH4rjJQ+v^FAzeX z0haH6!wF{&!ZZiI0VRY?N#SBLGSjas2%`>+>;K(Cc-~jTq9sm(6lH`2pS?TmW>4kT zXIPgmX{65>bwU;d#TmoGYOO&1yL4GMKK+zK6KrUP7;&=2<<3@f4Gb@vP6?eBQGr6KOuU`l|3#-d#M@pQ`!PXt1ZyP zepmX3R>L1fXq?LDtc6i(&pnt_G~6?zrpn*J`Z-FJY>7YS;~!Tsg9YVL1dd-}U*Cq5 zg2==~UcC-Cw-d9As((5isGV~dd;jzs8!$y#n7sXZbxiCc^+D9nNpQRx@&jc16o?ql zfr3snWMO~ffgA+OjLh8>Ljzo8it)u0szudXl>e{Xnbb3P)*$SR^4_R} zRN|+Nt3NgAD%EA$QqB+J^zjeQnfzHcgLcH?!8p;;4aNe*)u6qEB|tMq!i^WXXC*0x z??tnb>@e?zfnE9fx}#KZ|GW=0&F1Gnz4k+|}J3 z6x-eBc~+Fil{71C(cvLl*?*FuH71_2ibF4b!b*14U z!BJXU8leT{a}t3vrGEy~EmW_>E-wZZ4FRb)rF|gMseNBCHJp#Vx|=ya8Aa zFMI|DxQUCiY(oNOJL-V2(4Gi$O!64S(sg*X>4bPyWLqBBHG@Bxm$|!nHjNK!)vZP5 zl+|*c(%>J*60>a3p1YtTz%+iUk|NxDDgU5tq?(8bFb4!an zQmV8AgEYg<{hc(h=e7qwUuSuTITDEcS_0lqf}*dMnrUJ(_J2wnX72AEA)`$m^mHyE zBHT2|Z=uYm@~1Lx<8*dPEsXK#P9ntQSe&&Co+6zi@H{phU#@O@_Flj4I9M4wC+V*c z4V80v&sE-;MH((@R&A_Xl}YfLy|1Qsxj~s96EsvzbGzF2DC&_f#J%cxI!C- zG_3Y^L!+--LWUQm+kLq%+8Edr|1r=Fn_VN}iWS-Zg|WOOzML)#SC*G<1ncYq)1ss) zh=76Zq!|n=pkm?EXt|Wdr{1o0qFJIb=L9g|Pmr6!jn2Wnuxz)l3@E}F-EDcx#~|rE zI@Mxuu3YG4N}aBZNi8g!ph#?uR?`88ef=T?LA-19{1qZ#$ArCH8UyPoC%|O@si1cL z^anu#bTH0V!L8-14YNsHD0dw(^(v2eBd%9uqVHUNU2a;%biD#Mx+`1R!W?C-e}OBT zuW^|@n4zcChPf`;inTfXII!gtiVgfXu~uO3EM;Wx3PI&awPAdYhnc6pxIB!`F~FlT z&4}eZ%T2SH^?=fxlNCpP7e#7V-61R5xhZmn%_VMi zR;{U_lv}x`-&;-XY8)JfNe>&!sP7hiuL|W73CQR^RrAuuzEhCYIE3K2)hQ=b@$`pK zWI_g`LQQid%=>=M{s4ZVSduQ<49&zi+7){DiPp^Jl?(V4qIOLWl0KdaV1+9P8i^jj z9&k)8AwWJ&Nz|DH8j>CY7!@N{k(Mty!k5F95dsLUMKSP9b7y7d>e-Wv^2=ORnpxGs zvNInlUi>9L&T63c&D?=^P*>wkPV2&183vOQSCuipp#O^bkubFbNpo&mc`~ejLOz4T zAX`7gIT|#GvHkTolHNOaBnsB1h7Yw2vcS@xT{GR<)9_6@CvkLuIqPerfCJ^u`uWs7 zNasvP1~9;e4uY|X>zG8|08O6U1Ma_F&?1s5qev(NM#^ak=cL)d`DMYu8Khf6fzRzMp4fPpx5s>IX>xWHpkxz=w#x*?R54!v)LWPfUn zxx#;QjQRFssbfyS;nFP;&H?c!=*`dhX-z(vorsUX)J=~s`SEJgDZ<=^keKN~pE!DB zx~;eoV?r>r}y{wMGoo&*0SEb!mp5)>SGJBp&8vovlC#KK5ei*^SASvZ%t7gSxF{w;CN|tdjc){mG&S;PF3zPncd~`Gu9aM64 zi4mW52s{#3F7-|)nu)!JIZ57ma3=YHw;-9<57+v=)F~!8P2X}F^I!eX5SA&JBQB7l2Nz;e=EXD_!WqS3^> z{5YE){FxIuH5I%e(9Ei2zna5T&wiQvnpg)d4I5a*T=*tP#@Ly(N>C0fsGO-|oE{FF zoC0V~!)!(oL=BIffej?Q`PldVk;y~))Pi_CFT*Ej*p-`Iv%fS*cnoJTfLJaB;Sby& z!LHT2Xt+b05Z@^3H?$IP_YA?l>K3Y01lJEY9m$TK{=D*}aMDBp z`!BdiFo{7p=p#AZV@zDid8Q(8+yQ}7-JRnCEfbQ)$`h*dr;v$im-W92ZKB189q7l@ zw>aN!WuhHszceY8ex3*?txNKNiFwnK=`Um_LeuyvX-h^^Sl>!N4LCLMLkkf%0fmVE zhODE9H6GmD${3!=m@_5i}A`^x1KXx1gS1^k#Z_ zRzagWH}iGxj5mnRN_9QgJA?4lZ~5fJJ?TDi(Uw`E2d2oX!KzC9vlt?_=?`8^r0$d8 zQz9ca7V^Y?ngKA1#;Ek{>nfe;&(?5So1jQyfDPaMGWZ%!OA6j5Ou2v;aG(NjQ+4+y z&}im+4S(+4>Q9@mU%27W_cMQXe~9#3{Egc-_p@6yuDTJzH|GfJMSgZa+z>YGnQ`s@ z?1t$%UN58^jCa}e1mgBC2|u0hdcQ!a)eBqEolhZK{GEo&@Pe+(f^{2GHH zA`DXlc`yTbyjHKTM@iZ^6asnREi%Y0T$-9Q$YH`rR1J`rj#KtUe@Rk?4{APXBWU*w zSqRJAl8y%(+Nx_sLSA2Q9?Abqv*llXy!42<@n85DWhfw* z665Zsa5~|#eerPjlT{+_Km(QKY)qx!`pUPuoKf=nR-_efMBrr*;jL`edc=KrM>5aD z&anA${_A7YauGxi)-I>Bhnv20otFLVywv4q=2gLdl7)(yYSbx(s#8kD-Y_>@viA#X z6qir(XPI3gC+wOx6fQ$*9CdVqClkkS(H!mFw>=NjT@y3Zl#3f{3*#f)FNPPsomP$g zif;6G{ah=0p9K~it{$`&%L3pK0;I=2*A5S7lz)(Vg;Zn0GlI6=&TaMu2LJ$xP(fofYUruPcK?zpDv5-#;0hq*vfFzo=v# zt%~9tE5(*6cw>NVma*gic|5(X;E&rEU7|)z?QlAMjIP)vGCW!iXyDXxbsZ&M#z!WV zSk0HpR-)*ISKXgyg&Q7qKQdQ*E_9rl^!lV}IV12NzY6j<w7M~GHmfb&= z)e97sPXX%hNh6)Vh1AlJ>1$RKXq6@xIdT;Nzs@VcTXUIA?0Ci~r*r7>Sd3Bv z8iLvDx#3S;-~LVuJQGs#8RfRD5amXPxj@>2*RIDO0hTY#J=Rd#q+5?)T66Qa805`R zcsRe8)MOiP%4JST1Q|PiMQ9L-c1))CZ4{}E6bG)JmwUKJ=4@-*BCaz)Zy~w$g>jvZk7lz1 zb&I`Jb?_C*;_1gr3!i@i;3i0qm1SK(6Z@-5m^m|qI#T+z0z^xMbsDH@-yFNuH76D~ zn3Wt?C#*k0XEE!F;B)HJ9(rNGr6Wc4HZ%;OfY?Qblm4+!Q2(C zT+t)dpOvu8hZSmF8)Kh5J(d&HcqQ$%MqSaCAtB2XPif^A_PhR5i2oGU3S_b!EZNNG z(v+xck(+Cg4=ZfPRkG=2DeKk!pd>oe*crWHSgllE?LWKgkFd;RbJ-z{Gz%rFT@lvBaO8$q8($ldt(iI=<3Z}iRC z;Q+Z4GkG8iM-S*5Iw2Xq3)?{W{{MzOBQ^u=hfMzf#_l?(>0mpos%v zx|B@rO#_CUP(b+3|Al*MK8^NquSiY~f3M~44gI>mYO{GE2-SUAE-flYQZ{qbSCfUg zFh{naSlrI+SXUCh@rAtk|HFS`$XZ!g_NZO4?e)Pj;Jxg3mTkK2d~N7Cf=9&Y5zCQY z1n8s8?RNZmjeLO|rX+u9u#)F~s2k!f#iITjnz19ONW5k(?0<%-k*<&{*<3K8oZgg8{>L(nQ*%Mmfl>*Iu!OGtF)D9(k%4d>m`pxG7M-0GXI z!rEh+PT^Lva}NjHV=B@VL-i6*EpWl*Q2k~G>{o` z)_Iknvbe4wBnU+w64{WK=qtzvEsNB*Ufs%J=^>g3O_)S_7-Hsh&wuae0tq>CLQm-%uY$4pg@Tr584muDtC*`=ZU zL@_xp_-rVRi(u7X67nNhP?v0glZTR)(4#Tirj++Y42W%i-K1-~U8UJ$*K2S2){H*t zt;r&Dnft1f8S6o-ZuzL|8-z9hb6lDY#=`^6y~7tzY|;@uJOtXmy#>w`ky%mo+}^*HMOjq-@C2a$hEpf3s=ki)RdG0tgLlsjy={; z!M|*|f5%^n;OgHLf%*xJ9Mv@b8`?P3gkHylUdWizFM||Z;}L>aU%$(N_k^V7Mfwd= zz9i94nr-_b`_jqw6SaX;y>_Bub<=O!(>}V5=!p`i7e#t-hU8R+hsEy-w?u|$^ZNUU z=*0TjQ&c%A3$hn<39D7RN6?I*S3zr|}n8Dg(GETfaZhjssL9W`#`!`zLagWJ~ z<{^wR{00QO?*-?F%0hTbzF9Luv{E!te<^zsysE_fdTuR&_sGYyDph||^>Nz+&!UH` z1!||n+?^!T#1Rs@xWh(m8!nM>rGADslZkpen5}5KA#jl&_OI;8rm=&xm=E^`X`~b= zh%~TSy2NazkOl-%(uq*=e}5YA6M@}aKaqEb_%Mm2azqp$T;iJSu)n&XdLe}qDK;DW z&3}Rxa#@I6wu7L0u+K{=4g1FGTAd<4BevS2&)R9SFWP8AH@vW0oSKPWqgZf2G}-Y~ zzVy=;OLOCVJQ+%nalzMbjxkS^&)+G7*KZEf_2e7QIscm38Ti3ql)K~`T8d`4#_S&* zgR#-O@eAyi?+?uc4f4J9|O8#&2$5E@p)a|bP!&#VMm`?yb7 z`00i4@OJ-cvWC{esu&W?2Mf@=UJZs&PZvzPg!#)r;&vM8J-aM2 z$BXjNdEP(_b6(uqvIVf;*xsS%EaB}sl>=PhTu@M3)^o0#02=hEU+9qnGI2YLjAr8S zj0pY;6z8@ufueMmqBu{E_oZENo_B4j{+=-Vi|JIAKKZC}0Dvm?VvT!Gh1m0UkL5r7 z1L+kf+t()-lgM_E3!*bO^qF*pvc5 zywz1`p8nwz$nY z$Qs3x2VGouv>h&o0(-*z`?C%*g!w-@$c>Ysh_OE-9aEcz%nlzTeA}lvY)Ag?bJ7{T z1K1sPg>Y9%WrWu)w0j2!OC$Rz;tv3(Hgh!zqd$dn(&SX$NP$MzBfRe_7d#4J@bd9r zGnvZi9{7%#mg`M`To6Z1IH55iW7`}*wybel>2&9R8$>XAnGQ>Nm3PSJ)&8m+3RM`= z(kUVQ*i-fh>qHALp2ZNvy1)Q_>?`V^9E{%HC2?h#$-|9&xuP*poCEcs8Kd_>A6OR* z;R-6Z;DYD^pQ{k{x?@GxkF#z0wl8ucNn~^*QcWc5*I?4>q9l4_KoLJFnk9_?)PhsY z>{AxUL$kyz57<$J&Pq;)R>5?7W($~34^^@|=c;C6@C{^9FSdu%Q|t!l4FI7G-vN4X zdMBN(fWek5m@QbS_~3EPn$6ndH(F?EE4xAk-K?AO{%TsRTx^cA<~B=W?4DjF+yu!> zI`jbOj*dW+Y%kQqV5&efmdCoGk2h)XUMjkJ?ok{OuUqdh}|T zQLz9&=tutGc`ir-wyFTlH8o zx@V(6>Kkfrx;X2(N-ym%Vy{aa#`Zt{^wopdPVh90_6#W_)LW*DG>kCMkE9ay7UJ_# zKq*ZelA$2FCEa9;F5AKiB3u6{sr1zwJwoWL3330`Y452*G5sss?wI#try(_th*_p@ z7!t>BT&6w*c79w(&f-K2WXwkwF(!t8Pkm|{v28YPaZqN&XU-Pd?B-ubO{!0nW;T=% zL!%MH941+d7r4NSoJ#R>5e#v6^NwupRyn~B)tQ+mdGYlS8 z6j}txM)hgFdtCQ`vRq@n^`5{F&yvPozBfRl!iY~jL{BZ(uFIOBshWWnMJP!23 zEx`DFRjd!5X$~Ftb<}SgQg+X*Ds1~jl(oY zSgt{1Q{*_PqgiF0r-e5f1vf;0h^kccd?iM(D@h?Ys?T^x_81ZCw6@erF$YzprIX30 zse9~F27F-A!XP4;(<`5oxx*9a0$WkFQVDTWaV$L+BQOpW=KV~g~ z8*#p3)%7VcIBW(;0{-j7LGGV_4Za*_-uuFJS8N6VBld&X`gfD4xMapsjnOh3Lo$8{ z;0&bj;l>j1AjU@VafjRjwZS2tV{WDJv%u<@m0H>KkH_ChgUMlC4+6Zvn#Uh65&0M% zC@MKtQ(@3%^@&HoJ4`(%SYJemg*E_=8R*F?o2sV5I@Jmu@ah=2y9l51_w$=;9bU8` zZWOZ?aiijs8Vrc{A{Voc#vp4Mos@Fjr{BY#=rKR<-5wEdH4N}51)OXBcVxp=ie^l0uU*mO(C8Eb(5)BnZROrci) zpKQ%TAJ9p!@vT;*R~)xS*-5mSC`C=Bev59&QBm)YyoRq93xy9ohC^TcF3fmteo(n{ zYf!?Ad@^eO{djNU$)79 zO)fUDluKC6T}i>;SUw)Qm=`$6!?u#h`8oDUjP~a!hs6c$7+B2k+e2Av#?itJ`LK4J zjK;+oVnh{y+Ua>-XeYUXRP{C;L+g+f+u}fRzwYLu@^R$-YW?QtapzY}T9mx{`^{S# zonLf#7e2AOg=daRU`Hw`J4sIP;IuTcoxZ6x^0;FVch`j<){B zrDCeA1%ouX=oB)Q^B|jUd|CW4*$Ca;cY-3m&vZ>$#gLpsTiq*yh#|XckHy}1??{So zSGO1kbKRG^HRWx2)YXuafwHYgScEt?d_DQ@lfr9cNz)RDmC#9z3Nu zLRe!P3z-F~TLmfu%e=;w*%kf9oC}M5ePrDw$7Tgn_3kcXG&|}P-CQJPbna(VIA(7Z z?FFFDHBY`f{d{v!ej9VT55R{f8 z)b*kFD^R2Uwk0%u%~m5d+@Z|Q`##_(ypTCL*t0PCvrwDChu5pe7esrk0vfZ>u}S5= zyBA+iXUnIZ8rr&0RZ2Rlh3PWf_U(nAtl_Zu%u;; zuqK29nStdjJUu=w7^4nLZOWpPY-q8H=z1?>FMc63DWU3lqJKJI>PmT01*?q0k)i8C zg-bATv(tn&F%kz>-(z?7BR*#;TZK+9q<}V*d74z{zt|{%L4^zkmLWy(zioo^2&(6{?k^P6}?;zq^L0+2+E4A{6@Yh*we$IY(1L1(ChV;!= zwiZW$XDRT;RQ7KYq%9o9`QeO8X^5#sO`F}kvPlAL*yk?-x-(H}GFy9zfTK`ng1mPr zi;=!j-FOdVUara8**lRa#;YH&R=i?s!xQzxd8IR^=)z>!$APUIR+GCfXl$1O~?OGLCO3uX)Lq1$q}l@EQ=RWdXe!weLmEsi^sRd(ACD*erPF zwCjc5024BC+mgX%Mrrr?`U|26ww}eX7u5_=d_P9E5R%_aOl3e;gnM-m2^!$5-zdPD zz-;Of6xh8C)ufocq+N-;rKc03fNBhCe!V{#Wsu6~8%F!MVAs_4IXxaTcs=5iOJi1> zn8cm9LxX$Hx6-on;niseJAGz3L~ozklx?HVFj|PBU;={y)5MFydIKh^*O~494|}iM z(sPa8AFuPpeRnxDm!bGWcM^s>l4R9P76qFO$(3tVWSs#t8yEd$QsQ7%=mfI6aG&cD zjE8)NXV2#4T39jF&-VM;8-7oTZldBr0yEh_mbhS+Ycj^xVM?}c#P9*ishIdg(NE5! z0itnkg}XuumzjE%D%lMXpOkz|!}| z@iThQ-Tq;<|Mf0a$tsWcWxOlOHSo|e>af~#;ue1)A1xUh@vs`}dfwQrhuymlcuYy@ zJuM4+r%$lc9Fq@!2%{7_T<>P~!yV$xZ^BM^C)S65o6nErQR4>M zH{rI>mYx45MrutkjL^}~k9+V4xFP*Eci%Sm?-`zzIoLemmHOrn@2{~MYo(Oo#fv6A zVfLGs%9%ouO`l$iv9(v~b=ZCSyyKEp)>$7PGJYYI_D#0a_V^6m`2zgVa(KVXv@ZL# z(rmnFXSBqA%Sn_)`Eb<4xnz6mXPQYO=Gy9$hj3COL;7grYf;M02g7R@o$~bjxBbGx zVjh+)=eK^o{#-%ia}~H6d0F`}GyC@@+V8^;53-I4-CCbjjNyIlBCG%ZgEQ$%bIaAw zgEPo6u)!IXNi0F&LII}Gb}7*!&X&8S`^!*JW9zxd^=J!|i4Jzjf8^VU+tmL(M+--* z0>BnD9AoEj9@4-l{WFTp>V^?fd&S_ocz>(uzf*j&csBe?kU) z+avBqLHo>lOq4d#AiT|A^C2bXv(%}@U3ns>`Enu}Bs(w-H%0RQ;q5J>;@Y~j(L#bt zaEIVdaJS$P+}+*XA-FpPcbDMq?(XjH5G+7|ugE#)?YD1tkJ0zLW86QfP|4n7SF!hc z=9-Vp=Q9SpEwaL;k|Wfj_v|*7^q*pWT7DXyz3? z@F&}#z{ynSZd?U;+hx3-_qH~I*bq2FuLSqEq=Sf7UMLk*$l!Knm4UNRJNcD`C?PeO z-#Ec0bua&*N840hy}t)pMf_Sz5qv8_`Ps?6z0|v7{qXaQnsw6;Exe+fuvd(L?XfYH zW{wA1v7EOcP`uB_mQbSWb3tL!-mX@7q>6nlpPPgMjoaI-`bb^pn7|k8E%YsCA6pz4 zBOokFg$W}Yy|M?sqq;57yBG#lT0hf=xh3*swnnovHcw%y+)sx$|o zE0F)%q**j6S2e_ufmg{Hg0obEoH~U7TGdQ;I18dqQm4P*RL_rUSspOePaXInIp!F5 zPe1%;HV1)eVQJ_EzN$v&#~)phSo2FQpQL(d3bIHk#e`TsfSBAcpaw2t%Fa&*LWBZv z%2S2V1*$b!F>X;V1wffopS!x6XK3-{orFxe9H>3H{_h$*%QCRr~d|M+>dKYl6N zo|&fR@m;tR3eJ6HZ(TedPp{S9v)DK^nWL5_lcs;p_xt+nF70NPj~BeFem!B`3O;gm z8Dj{DnIxQlVW!}}F!Pe|Z_G4jE!^8i*x$_+l!`WyWXMssMO@#l^Lg0yzHExe$1NF` zqRTsuHP0wey34&3==v-W*wze%uwV4+gZ8K?Gn1xkq*GY306DXMv0b9Ux_FfM99Nrq zA7}$;B||Kra{o*L^okSLHIkSS*YzLLXlou@Tku1BGn6%~cA0D4L3vM$p9)HUs%hfx zH>&t5ay4VG-ZCj>U9PKCdmo^VF>vqHC0ZlvQM3kw#uFSbq0vQND`$3(L9O zDLfvbej#VU-J*Vh&zsZh?P>O#JBG$!W?QcXZu~Lqh_K`B{DQw41Feci<8rmtEug+> z4G*79l88yfT6Ka2!kS&g`UqG;v9aAE>;nGU4V|niT%0kA zhBpOnGl*h^GB6I>R}kw)85l-wY%6&&iC#jH>PB_p77gO21;a?ia*RNMIN(w`oY9k6 z1#_$f?7>BI6lOByywDGtSD+ld@CY0n5pXOqIou+4fE_@M*}0ERlfqbstueqS0KnIP z;>jZ%>*Eo8Bfoqx1tz-t;t*^?j|4^&AF`e<{Oy4jkNbCV<#OKPwb(96c(Ttfh_xF# z{&N)MFZ=;lZp#tTp6e@4e36;tL8vImrh|9wB@1Ll^GikZB!TqXTUD2Z9$na)W)sE(7Sq@XOB6iHkEz zZ$B37+o_nl$n*BT|BU@PO{4M%!rgapkM`v=F!do<_EFSLO)-`KeE%+w@14s&{S_c~4IBB=9(->nlfQ4ZxV#^^i~Pd(zswe7ezpFP zULqWCb*%5Qw2TWLdjw8O4$dcdM4Cev=$H@euz0NQT1T8=g=!P60BxS zZM98C|JXb^bA+}BNQrsQG5N>?0zVkC1-@_NYRgM=(Kc2Tp$x!tBNc2ZcA4K=JvYv* z_8UjnHkzE~IB|cPLs?sH7PI^0T7N9rTH2E+Kw?ZE?MT(sGqp$S7*--H2tJNN9z8=Ho_;Kv3Jk=kiu?pGTXw>rwvI@1ay7R4-{SP z6Rxs=_`?t}s8-~GtI%}W0||QUrl321|9#al+<3f0kAqn`9J%b>~p);gOkh*whox1QY|Jn<^o3KM}Pue z4U?s0!da_UtyF>_&UvaqE<>F~g)yHZ`TTln~QCIh`s3tP2xfj&9dbpKt(Ue zVo2?_5A|eKclGTw51^u93;Tq1^NY2{mil__&A=i+%eU-Z>`7g!Jxp@O!J2PlTOVp~ z3aKdtx}`qeahvP~Se)8Q-QM;oL&6oWwF=rU^#EvEb+fElb;KK1a{1_FETslg;eV^F zH68)K(z--FsI;#hFUIy8V2%=1P3}xT#Z(`Tu6F(*HSPChF{+;9Se6Uje6T^8>;9im z8kcL;vtiD*0frP-X@>pfYL#essE=VC7ZnRD`ByozNde^m&82S5ZDhfIX zM(0QlTs#>dqncl${~wtoFv!8pML6Tn)Z&hF`dTkHP_z4)uv=b1eS zRJZw$S|9g$gT$p5jGdluBWkaF*!bpLCVJ5IEr~~I==86^9K^o^b3D9bcUzQtB<36v zs@2h?AD${TlD3x1nQawzOy!7%m~34CZ%TcYUv2ND{?6Wesc!)KKbHE%MGF63>Nibf z{?}4pj#BsoAogbe>?dQ9<$TP@pUfPe|B{)b&<)JYIhLO!{UHk1Y`|1!6uax1K{8vnN5r}9q&>@zj60k$wup0=WA7eL;93K6l-R)o{X5fG^tp{w)vX$kj;gdY7oqrccXL zW1N(_C=k=qK^#ji%$Iu6`o7DYHnbE6(f zk~UyFq?~jv=w}2svc)z9^olZLV`D$mii9$QYh88Vx&;SW-WcXrw?v0^ZYVG+2)OKx z2;r)es;_S9KvfVX01Yg=JYQ~344vx;jg1-El*TL^hE?W`Q1DDj}ww2w*C~`oEXcUzI!=kSQo6v$e zB`hzQK{s;C<1CZqkJ+9_anK)Vw$C#MCUQhj(U)dV_fm{e;8HLlj8T~00wVFrmW~J~ z#&t|@>CZ(Fy<^*^jzF+^`12r5Z)LMu6TajHhqAecRDCsj#DjEcjl}=OB&j3M86bi< zb=ckiTAk9>Wrd$iLL(rbLGODtx5^ztv5;qa(?vN7Mai8E59Ct0;TmuYvt#}2la)b( zl@JtUM{;n<5_)lU&yR2V?Ndf!ls#6oGk53zAoD%*B#B&X)HA3?G0!^05;lx3mqZl{ zL>GFOvyUzgjA1m4rh$NPzC7H!*2f5x=6(P5wJYuq=)OBsKsC?zfR5>c0~ly|p%ZM- zcWmBA`h(5*zWYEi2eWOvI;sLPsJ0cU)UbObsWGxcmG&Pa)Z)7l>MwK-o{G19cT8A; zc9qo^Zv!<%WM@rGIU(S{w49!k%yy2HlTs~YAhOmR9ikR};i?T$&F)wwT^8b~o2H}u z_JFxUs#N=#2WW;|C4GE1LyiT_(oq&B%hEOhEo;u=kR##iB8^%BE#odRtID5&r^JKD z&;%NC3a6kWG0oGP)p2#UPG&xp_jla2tX=@tYZRS0hn5cWl03-4wThULP}Kni;phGS^c)InwI;)zXHd? zVJ63#W-c<&xzlMkSsE-Vpvs^U7iTOe#kf@`&0-zsnHAq*u zyaXU@1$DvmG;L>N*SiVHOU6=2q=U%eLdu;n7@7pLtq9S;MY9!xN5`-!1AA<2Q88>! zkji&sI4=hAK5U>i>9{tQ_$1828%?XO5U#t$t_H!=rd(~)WSAzdZF1X=0d3W(7VAKb z6WjeH@E8b>gUDAsmo6M%Ht8s~mcCBlhNYC>jjs!r%OtA9H?d-k;XB#a5AnM@QP{Oe z_JfLYSZ3HDE&;747k^`B=Aa-`I%Cf^kTb%6?~oz&USsZFS5aU=4-$9%>7y~Q4ex?P zaoCQXyNm&282<=;AI2VmLSMvS(aYdjF@FMUTyOSw>ZtGde@z{cwfsdL-ASfln7982 zb!30$5x<6l*5&(n?Mz}L#hPaG&7FJTx$~?II)gXcd6hnw*K(jxnMb*7Bn1Zff?uG)*S|JBI`E|0kiZgfx_Q(A8HV zO;(Y;1UEw)kG05H9^&ay3Ts}AL}#&h=LcR>ZIhAz*l;)z@r+~g5d;`rZu>Jey&>M? zua=^#Z+9$KLSc-QIxHXssShtPQj`oSIO=WEbM}QL;DGODJ^f(@N@C zmDAVN!)z>2ec|?RPzJ7Q^T5B_fm)Skm(O=SiCk0#e%vR+0eTox-#rX2F^V%EX>Gyr zNXWtKF$V$l1_A1x*?u7WwER|;vaK)?^<{aW8h8ciauWc{BJc*vrTSfPjStSWKIc#Hnjvc%gpaN zn7>=DJdFGaqmqP}Q=DmChrVsE`SEOrv?91e*HMlh|NYbt0o{C7NP-aa&Q!MJQZem^ zO>w;)Zar8%7G!a`u?}Dk0m__-3Ab43UC{y5&1Nqkn=hVspRM5NXPj9x`H{sN326(6 zD1GD&1;;b6E3~i3`Scs}6mlt`0-@F0r(Zny2}G6;kSe*N_z}~Kbdn@&zFOrYlySdg z?Qni1xjV459x(n>T4Vkxt=|IwAmqfq5Hc5tkbFRdWIp&CA&veZBu%eDEDbubVeGsn zc^8rB5Yfw}pNDbm>tab4k*~0Hq%dc{mrN{w4JL>$E~#(bY7edLAdLcv-dIF9*U#jL z7%rkf)Aa0fO+hD*t*CW-(X{vti<{sRS3_V|{0krOX)Z)dR-XE;hnk3rm_QDhh|2uU z=KxW`@-?OeE|pKR_0eC4`}3dorhbE@^3C}}`2+vi=9OQIbs);WHT(ckA8MQ+`@ui_ z#em7zSA#E^VnGO_qehWT!R93w1MXUpQ#cy^ zkyB)e9CS$;E7AKC0w@4_)Wg@D6G8fpTK=5965Fan9YC9|Y$Kpboaj#oTWG!%$bI7m ze+)eYMRMNOUj|6}CSX$#LOm1xwb(( zX{0D-n&!CEyD|D#&D+*joXO2>|Ia{SD7cQm6{+F`XOs{tmeC--H!xR*T$=;dDB(~t z9DSBpv=@H%Pfkck>;mO9FhK*tdWny%&Q2XM6$cnG^1jLwG8|$eJIql0m4Ok;5tBUY zr7ul{>D!lXMt<<%U-9UC2 z0muvu+aX4sQ{jpJp{Y3VBp&x>?G$@NVxx%P8L29&m?)+-Q@wEtA=qdJbyX&?V|L&> zRgUTJd9$$*3T?_3CG4!Xxu=S_DcLl7;AjSZis>ajr@je5pO3F!*%wdl5_TjIz!-=v zlo>lv0~*fvYgsJif1j;j80k{0yTBIqp^wDUfDjtusYKp>4G`LEVYEl4qe`dCK7 zUtfu%VslWpYy_^7L?aHocHnj%K4R~1LRxRww z{vj5oj0;3AH5;q&m>>f_d|gi8V{jIU0bO=+LwWl20X_CFk;uhzGlG%G-{p(t7|*du zy*C_-{^vPGchC`zIUVr26SXILcqzTyIPy67&7d4D23``hO!D0`Q(1wu6jY*p^W zg~qC73$LP5h8M|WNuU~SI(b9?gmnOKbV82(gt{7Jpp0J~}f(dDN;xd|48h2+XLWB(y9I9g2Yn$oSY}565~&fs|+f4+RUw zMIW$EV?qdE#c=HUJ@dg(GBQhMHCuZw<-)A}h9}QJ40~#WbJx*dab?0u@HT%Ix@ZUDVbBuHx zjGdg2F67^Q`Pam!3v{OH+O)|1g%!FPdT?*9OtEK+U6|`btV};h8Bl>pl`S9o6!w0Z zWp50E@Gtx;$H{aBKQ*YOWfN%;B`&e?$g@g}3M))pUlCTUv}PlAjwmPxk7OP{G5s-m%h7z{C%rtY?`=}0C{wiy#SFVaAEoGnfJq$ zbI?f8(gAUawb4kQj%{NUZ8>mBSmH?J;;2Pk*1^Qw0peg<{hMEV&(VT@-$|>)B02h( zh6N1`U~XFUzu{tts$O>jS>own*_pPtxC7RCCkU;XHQ)mz?m%INu%3MaZ1Pyk%46D{ z36J}yP|cn}7@_Plb6Y24a{RHOf&a0g@nO~iZD<6Oz@Ve|dT7#hALh7u`#Rp@Uzm!Vf{!uD1)J$G%j9a%-64np#K8z_X|G#Z+Dok8K*UdAfg(GQ9flq70Xt#s6VsH~wK{twR3`BTE2eWYrn&0{+Fw z?)FYx{msb!1~Rg-D6JtGxbycALwO8w2erm#5vq0A4}j4WtvcyE{;sWD!{? zJw?q=uY60bW@Ta6f&Q#gwgRSPFzBdkc2n{LX0I-fZOgDDHc8ETcBg4h?Bnwv*G$_9 zseDANxAGSUm3;99dd~?B;T(@^QP`{S1;{Mc3NG1>lvZuBvOt(0n-h~9 zYQ58Dzn2Bh5r)Cl&m9Z~fjO=V%gBY95+U< zj_Ej$1C&}T*<_!r#o>;ZMgq&9vj^s|;dCcEE&hOY<`EMhjALv=7VTw=D{ z4zklU9QRG;e=>d*kQlnYPofU%Cy0Ft-~AN+vO#+>BN`60u1<@l7BkEM88wvbXoLLd z4Yn??S<%a{irLZp1mt1_X`9BvaHC`K5Yw>1-_1DJfT-Y?sNjFd zuuRDJel8ZUp9@DLJ45jcOZ|a~|B&uz&B)7D!102SIdDR2_F`=xV+$dpHQNEh@xpIH z3n-`0aaf$=a)Azx%!xd%aljC1ce-$Q<${uG^TX!zc&)nJC1)d6!R-gBo9i?_c+Pkp z^!z5k7g&~!UhKZo0j-znE;ZC@b8vx~vU4aHKdq?Z<|cgK;p7fXgX6Dlf&_aMt%%{> z56@W$-8Cv&KzPm*@P+k6`W<`DmFRJCG%NcjW z=;d<$7Ue@M!C(frTJO=Yd1+w6cQuUtk!6MF#%2<$1Sn$hb*P}8kSBW-Q%M~RrfN9i zQvOj61d8y0*!m~y9s0OEiE(2+A*)x52AEs-ZW1qs;~7sxVhbJ(J7m+^w8*CxxW;uh zJt3_^)oiFhWDz1<(@q__$VY4m1HB%<_MJta7T-Y5>BasOgnUW1Q>rt8S{TCT)gcY6#fAKQ zm%puRR`yV)pC&+{1i8`6$&9O@_=m@lZH&`<=Ky#K%S4b)!kZHjNma5q+zB7j%Ds~y zv(O(t*xwL*V;HscWB-aJyk>l7-E^^@8L=9n_$nMU>bJ@+*3DxpDb>GxI~^#QtTOAa7ku;8JW$Em8hs7>UH!zRU@?lFQ@xk?)i|^818O zS#LM}Z;q$-*Zit(+phNq-#R_sS{|(=uz`b6uw>5F&v0(b7T|0DmwrR;;ed5}T<$1|Lxe`7H%lgzNvxP!}gLXAN4A^`; z?R?$M0J{hks*Ch6xqQ987=K*K{>&+Igt8_Q8N= zJII(aqso}mWzcquAv96M=AS85Qe}Ay(WD^UCjz-!+ks^b< zZq8PNP`>;0iPwx^$4KHiz%}JW?n_%bT;I2+-J8c_NQ@X6;sw^B&gYx;w8>qt?mf&e zvJxzWA2sP%PnXx)==ma6e!y?(is4!!Qw+SU*k_K1wY};;qrJVdem?9DzF4MciMt}& zq~g0dKg7^-A-8g(t*qz?9c=`r{o_e%vx^^}F{W3YnG*^QkJN7|eUfvp9zJ%Y&=VQ2 z@P{vlI)o!J$Cq7TYlh>fsoD|fqrdDhlXVNkR!<|yk^aIjSAYORab?cX3HMm~I98w% z&OAp4O;oE}0!wkxsT}S`ah|Bqes{J4j_wls0Tt7-Q!5x1?F{W(s%~lx=At=m zrH#NS?0rp=v7OaIcirVU5pK$Gr=COM96W3aNp&70eQX2oL=3N|3C}6p-+89epjmj{`<*LI z@c?Vm*3qWj>FU6ipfhmK-+6`yes@*lrSsPyq_(EVpAIYvKTrBsQ`$5~PFF30e>Mht zH}r;8NM9&l53{pEGe)8jgoY3?=Q@{4Ytbr;5U{^?y7r>osV~98^&)4A?`^1N zMW6z*<1H()W3wuEv%@5<*?X7cw+9lwjjs3J?3)Pw$z_!b9G8yEw^%&FV4Z#<>gR|4 znK8O>fu?zsnrB39B^-iztKaPp&K?_E?uB>XIhd0AttmFTerS;qnGlTDUs_(km^Cms zt83BhKh&m`Ew5ORO3dFspV`+kKX^1ey(rNz2|z7MpKe_powu#=a*yu_na9@sx(aS` z{i;A?J7#{va#FG5%4O}qaRkGMyep~KLL2q*4vg>TPkq|YAkF~i7M~3B-kTP9#Hv}| zGZINd%_$wk0{1L`6(=qmaI<;OuplmY=+%w1sos-vSx=x zR2|b#$=pW3Khtvb&BcRK(HjmE9CNP!`^V`LqM!zEQbz%H5X@5l90{aYPGRsy0hD0E z1p+v zhU8Slh8#%H_at*z!SEA(BN<^AMWQ{+@s2s7*@OoO0t7Rh7aZ%wn0v~=bb5C+H!_opcOA;~y-|EKPBt9+KdRL~Pg40F6tR1?j5>*Fo4 zHnBJoeNEd$-LC9z{g2@44-sD^vEmp=ZssR5EZpG@3Wf*1aJ| zO-_n?nKI%+(9(PwZ*2K9IOiD1q=a*ossXtKb8bZ@{lOpg;J0S6ekrbIE?Rj2vPupU zL4Vz*YmCH7z$5pA=4bd%YShY)F5lN`K!H9(ek!hAo3X!%Zy87Y$b6SZ@Eu0T==~Y- z1LcpAg^niX#e@Q-hWb>@1VzQh2MWb`z^&kuoe8#~m>^5oASCNV;Hi61hU?aWRpkrt zX@SVLKOHQ!J_Q3vtwHq2f9i95KbH?EAV$1ei~E@gb_#~Ag{N9eB5EeLci#*AkPT8 zvL>#I)*hj*4nxj?KV)8$>z5d(TAdTDv%RK&E=A0IBHlvYlE-LL%z)B%Ap#_=3>F|{ z=L~#KlE^Hf0p3B2Lz#m8VZuXzTtT zE|kj()F%t@K@1u#R^su~7G#?}fKRJirv4hKYZA$0AK?9D-Sr868Z?}+Yw|Jo=_Rxi zgbIYpY36$lHzK%fiH_n40P{Xio`@-cBpUGjDg66xggpn1qI%LBtSq?foZOP89TWw> z+~lHQXo3L!Lijg?>|z^=5uk@KpPWW2-rHi(tT_?D3*gQ0k!e16TW>%FN=G52 z7l9T-R*UefYO{GgpX)N zpE&dU+9k6F`$E{C$n7zfR~$u@QxwTd_M{dX zM;CrqCPH=5${lLeVMsM3%+Q@yH}k$ozX)0p{b{)mC_f^(J_{H{yQVw6;0?>0Oq?7 zHZ@CntC*%eXXWmb8LGi6OOSI3OOOx~Arg4HdL^9$96r;cx{q85Vh6BmX+BuKxQjEk z<4=F3`l%aFh*c2yvp`E_4~bz=0P6sFv)X}vLLjHv6}$Ck*FmSIum!lz!fzySWdJsA z!`b`{0yv^TY@(2D0v60P=Q=OIY^>40cHwlTSzi^d9phdV9**J$>BnKhyE-Je#+wr{ zNh1s7pT@1@3Yx- zve25qlEIQ^KO88wYAu{Qccmj}nxB`wq&~5e5QgP3LvkZGg1P!|)F=1Cg_-6)_oUy* z_;C1eWavpZuYS;-Kr)bi2jb1ATPR&=#AISe3HoT@f8y(&0IpF84kPQ*0EZ|{2l-ON zT&3+LVpRH~;5u0eIqBb$I>|SzIx)Zo#C+wS8;&F}aTOmfvtt*EQAnRqyyDHJt0*r# zgSi_zM{NiAZFz$FL^CLoho0eiW}C6{%a}|lSi8ea-JH3m8H3&4!tt2>z#Ld+jbT0p zaewtj5Vi$4a)M=;x8}8+BV;pO6R|_1U=0vC$-e?PU$aqe*2ellv*;t88trDAeZl%| z0QQ^#>Grk2C8ZW@PqOWo6r>0`zclS0RGdDEur~}e*bvB23iDn&DG74j6H*4%;fC(RvrblRWo zh!0mxPXjxXY%B3x@|l&9YnwAEcbTF*VJi0R@4t<&E}tAo9JD-vdu(?(t5I#Ao=-Mj zz++wY?LR;NoS{jZTqmZos~=+Nd5aI}e0{xlnk`|HGVy{W?AQx`BUL$1X4Kh#MSNsZ zu_#z7JD;qyB_b{lPy3-7=(kE8kM?WDHT*#6rfhbjBk?A(jWg|KQ@~qCf$kyTgMIM;o5k|We$_9daD`dMCZG`;@S8~&aaqfq9E7iD3cG19% zLcKdyyrhk&rrM3DxV+ib!>p&NRWo#Q`Ec;t`>tE(dV0{?`_JxNx!1+FtmygV{gG>^ zF1+v)sazbq1701jn|ToAnnH@Ct2_BfrdQjhSLS-I>pi$75agJVqXs>qg&gNNr8B^M%n`-S6nGg4T>6k?t#HcQ z)h66SX{srBp(I+PhvMw@LKKw5WLL(&vnn;~i{+tTkmgk%TRvEb3q)P0|D3GVt{`SI zk0V)S9n{TkgmlDHql@^Vff+)M6}T~AYKi2FBm~Y0o^YGjZMA~q3vv0yUj>#p<4GFi z#=4^0se-_eNIm43%+L~qw5#p>?%`DX)>$YZlzHRC3dG%m-Mv*EQ>~GHaHI_y`}@WK z63*g!z6@PdNK~TR1MrL^+ddGNy)N=}aQ3AN%-5D90S(#R9EsJ#A(YInsLK8i=vq5s z?F>X0Y~Rn46BUiBj0Hq8AQ8hd zB7x$PDNnEcoN1#xwS92-O8H(Aws_b!Caea=X19JLT`yOJvy^dxsvPxh#E7R0ZLBZd3UgKo;nz^{T|t= zl}^+1{76^{TJ{msWo&X=BJRjIyX%Xk4Cg!p`IXat`(+hF=t)P3Tmc&sT;LV0t?lTF3LbTjq4`h@jDZGRi$OJo6m$Z`3ra&~8MUT0Zg zEbx;*vgb{0MhFqNmh??QY;YE?j;Yk%ooVpBTECZBzW4a4oxm>@X61R2K3=tM26jV8 zz{-Y_32(tBE~5N9y^Bmy{$QeXibbC0^oi2vHLma63Tm2-CSN=ry4yzsw>L(>{lK3W zHVhmxTyHh52IuWgE_fB$;sb=mPEg1`Ld^5v&I2FOQVq;c8-%;9p*d=LdwVF-J;;}; z5s|K~!H^=NE(U5MX}1DxC@F*_Zs02(x+}mN4|Juq>@5Ah?qSGt1HS-_gGYLOT}Ht3 zN2u{K^j9O$QV%ic>(xL8;0MgG7m=$>if}U9n<3T6?G=gadt~N|OU~Y6Wa&W&Zsa z1oGL1zdVC+0(xTu3UZ=|#4n1bX_co198bY^%h+vR28LT2YCKMWr7ycSI03X%>;1kI z)i`CrRx(Ksh@>Hjkvq6p=j|}QvbkZP=wUX`($7&&qKNK?9JJ!+z++ANd%aUq#X95Ht)9{bGY zmh1H;qj%@@ndHY|C4$%6b)2DDzGu=NdiPhwwbvSVeV9yc`$|jqEj9u^;J%HWS0grRwpM`X|c{JDU~v?8WpyGX#+#RMHBT2F;Vbh?d}aTdbh; z2Hzb;pJCgezqkUIQ2rY+O(2P%N_mKx1NslP95gF&f z#+27`1=x8w$u*F32punqp3$RFCQCo}48zst!V58WGA>4qC!YJE zei-a9H+;+Rk>KhOwP$o;j;p z=#crlNMu^fCA8R3v3Q*2siu(?^?XE44#j+*TuE3jLzhfj19phClXOS;(Dcb1FK!uY z)!dcgwjx0&$ zN~KlVj&St$%1(&yVb7y+eUwiR)iX7TScAQR!pBQt+g;}3IW6|s^ru+v#X}*>%MtH+ zDkwy^YQR2G2w(WzeM>1m$A9K=;3>GkF2VZE3JYE+OQhO?U8Qfi`gj&WgYld~QAB}` zNHPq?tgu3sILuwCn7Nm#CpkkltS282^S!l!Ev?^29M>myh>Q~~%uXZ54TpwDT0zBW z+_POj&X0=>)v7Yoy?5kzYf+!+l~(@E8P~#Mx?Go&b0xq1#59eJa-6wTYW9aMHVZKr zVS74P5&g%DtBqk<)z8uEH`b5UW{Qw}m)mg$GTdkDtum9P&1R}DXB%7vCMWlI7#erZ z**;4zmKk1Zo}aZJY(|$i^j&4XnKqtWhQE2&9RTO2PYqaHXn~fmS*Wc$oOYLbM(*oZ z)AcV*Tq{f&f%QfrS!C_xK-+w%^sXiFxe(a(n7if5zml7!Osd1vvMF%VSzbftDVM^T zm_V12?ftxthPs;8JdGIFv@=B5zkx~Qt#rM%N_{1ICo}S5Sn*Q_M(d|WqhD8ofTY{LsHz6KRI(%iSx1ZjLLv+dOQR_j+DLe6*;*j!9qR zWT8RMryD(bEIT_5d{iiPO0l!MHmX)tC6WMv)%Z`LudRXdQ%k3tfxLJ zBGalyqh(y~iCXqek#N;$L1H`i+M{V)9TgTINi83m+#^dlJs~x1>t%+L7@DcL0(1FZ zYfsCp@FY*P8F0%e+Z}?a4izwZ)`DA@Q7KiB%%g*;76k zCoRS~vz^9r?y&~Dbjl9&mq$B2f%%K0Ne%UjD^5mb5i~OSSufdQv&BK9yJ!dDv~pX? zwT*r&UsM%PQH1ER#(>k=+@~Uri&J@47k8A#W~TRfzTxD#?J{%YvDl)Za`U5=g@6&-={*Iq@b=|bHlkB%xiH|Z3i4xL z?h^~W5NqoA5QVD74Jk+A3JXvBYZ{(UIUF@-WuJ&HiW;%PZdXAS{EA@yhC&WrAcmE3 zFn0CP_>$}PVz$YvszHuLdR8?=Cg#$kS&Aw&Pcnb*WqU@YURhB0PSEu?W>P2}0ZC7L z*=mA90BN{vyg{wndF8nK(U+#zFM*~>!!&`jg*Mx)Mn<+|<*)^9Jia#Qi;FCBuq=~e zyUdA?HGMyVvNv@^*}Oq}BMS9TmFj(dSt;QkwokAxNXl*?^e}aEgd)%D@@Q`8Jtyc3 zpJeX5B5>x(x%&t-Jx{8pCNobz;xf=a;Jl^Xj&$$nN^GY`<|@-50K1-LJ&NUN53PAx zv{lqC$}(TA?&C(usQPh=lI-M_--EaJ_f`DKIZJ+>sM)>L;wpKPYI3%P?Dknv*AKaS zOkaEZG6AEv@m#SUcC`l_8I*7|?oM8#Y97J#>FTK@?^-aHyw|_nH)s);S}dws=N;sJ z_-gQ7jkXjR&d^VA#n7Y=4s@GoNZXofYX)h<6y5c#2Y1lAx^)G4`B}1aQ@+pR^M+ny zHIA@Ft<`s1Z9xvX$*FZboo)DJRQXaKlWhF>hLM@yVw7a06Lc_xWmJv&s9$yaG4<6T zr-Styf5lNqgeg~FjrnWtiF*B-)I@V0StMEx1*NnTtoN{Hldfu-Kbx@(E{_U~5)V@? z$0;3`Gxf&DXchY%Fb;}XX5-w~{3bzX%lCOp=^GY@J+pV+Ew9~NGVD%X&9shc9cx)K z9qFqhMmV#?nB$8rGp_)gH4?Q@|03;UI9b+vxD=I z@;uBH-;RhEyF{CBU6prk{G^{-O98{DNPUzDBKe%sD3XZb&dW9hw$lh2=qZM66uQd; z_2S4_arWb<-CauTq}W!p>sP1^CvhaF@V%A150jxGOo_2zCkuEKD3nlP#~@$#FVdTv z8B2q!lr768T-WyC)0qYT4AX1up+%8W^zMs!QMOMh{YhB&N?5^3#K0_tqBw<&6nGy- zhEC8ahgquv5@m)^xraF)c|YPjIwb2tqoL(o?rw<4W0g z5(jms$ptY5*Qv+S8%Ah11R?PaIZ|ukZ`)*J(u$baYsA50o)eCv6*s$}Q9MuSY zJV)9OB|NU*ugX%ue#ITXWgaRXt2OC6M$Fo&(BzRRqqlCAiyCGii(Au>*F2VuYaTn^ z4b{EIGP&%P;_I$$4qJ84Bv7JX@!j?0iPxI?d#qwipB{1s9a-t%wlWz+5A%}7;t2;m~z9o%&ZezZnMXC=O1Z(G4?OU)XtT;T33er3i+ zovWm?4|-Q~M+A8}hJai4q5(pZ_$e-6Y299kNNtX(wth<-h>G1GlKK4(uj<7aNXj!}_zcWa1 zE-4}Y10oLB+_7rP3FYPujM5c9PW0qndU3VXzS~~>B(vtC35ApH10na#>l`3a-wq*K zJwIjC+b1^V;!qZeBavvRp12EJG}_Zx#+)B@#&;W$4SEDobwVs*NEIfEq>;HTxdBsr z0ZT6uEh3T&>_)=ckkItr#-GZC5-icsZuH23JBAyKThvKz{%jqjpf|(#k z;T@vA)*j6!Kl|*Lf_p-rSVd#pIXcRf!_bxS{-5{*)R8YY;|rJLhsP*V&LnR!vU;=_%~h!rcT zp+Kvry;N?YsXpzUc?#xu)}_84*w$KeRuTzBR-6NyQ{ZL85Uh1qpMi)kH7t_0sd2f$ zo_jr23b`NX{=N)NesMld`|D!uSNQO(Whr3oVS?_r_X7sppjWI4gB|loEm1u#GsKGSv72`uYyL$1{E~${aKKTzts*|Bl7FT zyP{eaE2?g>!z2jYyu% z;axZ~v}S2g!s_w4^`_R5`181Q+G@C_@7E&G@zular^83+qKx*jrqR6yow|g9=DGuq zQ}dj??+Vp>KSLp%lPX^tNxpcf`g zs(*_XLW(7=)5b%ncy*LskdsTMC8%G?ivK@teFadPLDMkqRnuqTmwU1ljPiN}Cd+5bAH;u=G z9)2ee*|wLf(F1opwVm#injSn1OSK9^cViynv)4~0DSUz_1(-R25KkQzGGH0YUhM8{ zm4j{a<3k|te|dbr{UG(gzi)iMan(JEk4 zD(G^8KqrnpP{P2PXT??FpKAMsROUsZsx;PDUjfR%Cg>f32Ehj5orD>A-J`#6XS)4F zL;vFmJMX;qY})#Y-vr4oyV;T>T7>d4{bw1!&uj9B(9ab(=ek$qOON@BTqv4!pDWRf zALTsqVNj;UJuRo?*^mhpX!cH*=>*6gyDAKRuwIZk5FvNliBEC$xax0ioN>Qp#r9`X z_d4pUp7BY9dEr$95@42Yz2_9Dgf#@OgZO_8&C$-ZkIt8rtCB&%1jmqdYHO+8M~;#1Y;` z&es`~ry{!E+}N>n(CG{%({j?y@rYh z)SQ0>d+Fd=zoi8OYjsR>WM83W3#Gn{os>= zwN%?H*0F|vB;CyWVLOTH~cyK&;ysi`4*q%c~7ij zWmJRghI2P6p}nTaNq3-XAYbrGF-bY}(`V5bo!q$q*N;0#z*mLV&K6e0QtzG1G`NJeORbn}&X~CNpG8&0av)ea4K^s2XCqEK3Ql}L>oHlpjyWlth zHLJx`Pu@&UWpFvCk`B~S`qoCwxvrJ&Cj4yF9u+Y!Cz<*yWHhv#WMKc6lga;K_b42L zIl))|sqXIR9J12)Z$1 z*_->?owRkeaq%&ZfLob^jq81dbC8gBP{{Tg&oU}{^%%8cKS{j_ePxDb476Z}&7=)U zH+RZ#tgYC*3!G_Z-_f5RtQ?>ot^yq^9~)=>1Tvz`S7U10izRFA?jPR$c_=z9AE}S@ zntmwiSucKoOrk<;^VUF(wSMV>+3<9bSbMNsj%0q{7eC7EKq80y6D2LN7(BbGadWCw*F3Ml#VVd(SMIwomW)E-u;xsS51Na8F**y zdzVF1|M~gty(=Ttg6x<8w4Qv5zW1B1zVF-F2uF2#={h{3VPK-wRiY=6M14f;(CMa# zQ|fN@;xk|qUz(t(QI;n3W)=@sH_@`v2X|>h$E#@kRS_EvyA~W@bEcdzo^|M`{V?~;&y*uavL||FwRM4{yOp@hm%0~A z|LxL@T&Smq*rg;7T^kP2S)I+qH+L=BlK%L~_1xzn;p{B7wvO2~xO@Dm}1Ppd` zxLN>&u&}M36iNj&CvSG0wr*p7s&f7}MbTOL3~@5eWXDw!?b2~0C@t& zb8VeHX@M4mUU{go=#Wv)VVXcs)HLZwsY>??PYRYC-qbsVjSA?$dOYY*32;)ru`5Z-#1L_gb7d{a|Xj{W0Z7vpsfX9WhyZypUwE4J6#Ikq)}&C zLe+n@>m_~tX1MA4oS<3$?#7;&kkRm&u z*4?jq>X1>8XU=cMD`~U4&Uf_saR1Bld@z^qm5faxsMK<8*2PrGh`1jp_t`IZG}EhG zH>pzope@~01pXF`cCNs~*4N)bAKbDLCLA;oelNS3s{HALFypa4+|s-;n=a zwKl#BZRQE`zuV;E-Cks_oQXIJF}$@|u3xVG6ALwYJ%U@Z&czJNY&@p#%@}{B-w}L! zb)Av6P(lm%bRU~z-ePH8x6xr<_HZHPe>q@&-R)a?6=vI&(sQ@m48P@dx<4vF`se&G z-@kAFai24)l+Tq9hPF=lgvqQ(uz3+jFiggzwa5bP(>i&FHkr4Mphu87tLCYXW7MlL z0asKl7i1ofp|z=vFOs4vsB7$oM{;s#+-N@Ou0G^VHU9!umsdAdYv|GvrpA0)Y?j|j zslPsxaA-y}jqG`)^M=k(4wuNUtx#OuFW|x+mhQGji~y|`*KR*X;AJzCyDVGwnLUG* zS*c|lwGq$T`eR;E;jO54+;ky5w{8GXyN*R(NX?f}DPx=IKjst7hYC(F*DsEnL%2gN zk$=iQ-L{*oX6{PtVI}r1CdGIzLKs00onZLS@h9$nIimK=jd~urgXhPej^2lQ62M$M zeMng{n&IX&P!m3guBN$`nJBzB7{ePgQDrv<%M z#C{JO*MSdDPeboP>oGBv^@tTDsg^1x79|=6>Z-I*fTTYBU3*nJ1sWQf8af&ws*tm> z;8Tl^eG^wRhKv;7oOwx#Ul;BR5FzR&a`nK1n~ z{bH@pDX8CF1mV0dh~Y#c$d{hx%Z3H-izAKsFzmD9~ReDH|>l2 zIeXay?IB=cfOGG9#-{(;#Ga_vwDip?{9$T+FF)iWZO$=SGgsjWZOf|b^LYxvaB1jvw=2%uV%X=h}&|(~DpedZ)~$iV)8^3O$8XS_nTqc{$OV_+0#cANGxHTJ|=Lja1X@ zYi75U_`i$B3^x1K(K8;ui=S4h&+VDZcNGgRvIf;!bzg*TA8os2oHw&|#u+;bmJRU; zedPyF*gdln9BGf|7OTSJW-{&-Fk0_&Ti>s9>WT}7Wm!)@3%G5BA>-^x_U>a-{&tCo zvP}b^X}T#>Hsl(teiFZ;0oE6nRhP>%`Wkt@(;*dRBXMMNGl_XhRw|77WFApX3Rjc( zRHUkR{0m)v&sTe#W)CK~4z8^0JGQG3=l7d#GRTcczaPgMo!i4^JO#4IDZhfC>(No{ z$!-c=nLkU!YvSj}b2RH585a+J={t_v$!-nF_YxeV+uz<_EQYhdFCJLnY2hqMH|aYW zq^X0e`s79~qNi1@Fktet?h5d3w(Bx1-^Qcyy~r> zat)5T%xX=p1zr8pzDraODAcN~k;hen`Uxkdu?_#NnmgF3y8J{?!FHp0F-kGaRuKwY z@T`y$331ZbM)3ym!4-1XK{0IM24HVX}FAyy7%>4fE3XzYExHrd+~q<9LsF*?s-h z*ifc`3wwhqO@@U>v~23=RRPU~8Lo1?Kbjq zI*A-IXsxU7Slc#o0w+3#>yMj|Q_%&3fiIgyazdg;U)+5)%BvzDj}HviN&ou2FgR-7 zw%>6VJ7Ri*-tK2Ga}ukSRO+;0rbPsgsD3t@6luS*-Qi@W3R=O~x{5aLZk1XDp%Zk{ zpuU^71eqvrd5=P81ENH$GVdc&iRF?nQK3XMXWi%*2w*-i1!6qx*C;2V`RR*k0RQqE ztN$pQSn?%nctZ+{C4QM_hc+LPbwmy&Qz~dM;9W%{f7CSU7QC85fRZE02Q;`>V*S-N zprF-fCev0xIHDu8?Zpe$@Gp2p-Htk+hhRzX7!8sw%ygKdN-gr)iZY+Dgr<||kcp7> zhm5ueGxW3RJe4o(W(&hNTS>K$(tcy8Xt0aPjL;O(9^i7*7rC~296IVR6!|(lxG8~N zAK(5Px|mLx)CUwNcAVVzp5EA1Iu=p-{g5zo*50FyfFGGuQ1;nuq#nxQKUwAx?G#%$ zK?O(`|2ji3a}~jNuo=cLI&FuAqFiOq2~Smw77z!8MsZb-2igytVDQAwdllhkUHwpP z{ihKf9zcC63&Eq0K04)t#4W~CLX01L(FZf)%-5&ewNrnSA3yE`UG_pG0<_l^x0O9* z7}*|N2FzI!21DmJjFIw46j(ke6=_LUA`)dj4NW4-mt;fhrFvT07VJCs_vLbNM1p8S1z1a1Fx@ZbN8^!WF!tgDRc@>R0Ql>}(7{A#UKlJ85i zheV>UwmyDDhl}gtGZbPKZwo1eG`K|%iJMc@zRO{zvJJ9~5`WWRVwy0fEy03~jgR1G zPLC#$<$hxT2(yUIbB0y?%-W~@_)LWOb!PUDd`OHe5g|(u`3TF62&B2_ zb`Q%^Z)OfJj<8Qob1CQY@7F23*_LRQ*OP%tWGRNH4%X0po(DTizBJ)iS+)gemM6Ke zJ#^LqM}A?)Vs!)8`R$%^34VMCg`bWxAu2!n(qf_9{g5x>DA28#rqM+5WLD4`&+G0e zIx>?;gS(7*X{V1ZU4pMlonhh|v%~cU#ds#Mp{JNzhmDRczxft_u|vc~w~0?G+BE4c zlAZDqKC%5l&WQ5HA>j>=(?}8wgyDb~JG<|Z%W==D2otm_{ZhSJqS+ciiY{;r)*4Y3 zX^Za3{l9B+RfF7wG2ZHpfnfp>9ro96->7|MiwR7*Z=p3*ScXN~=#`%g(rMlG&a5el zoq8*W+3+)dK)D<}?e*FCgP`JyCfQA99v39FJjv(5iyAF_VdFW(nq7olq+F`^l;17N zOOOq_%j*9uJ3a*CDbFYZast1p&ly4n-OhZ#?;}r~qZ*}&v?7DRnrA2nZOGK|$#pJS zX+6Rf-FC-ffD@FY9F)%OdePNe<=4q8;|7!W8#V9kY*~@>xw!| z(6n%{LsrkUDSMlPBQ_o^vg0f1=g}8Lkfo=S-G;97PXD654)W(s<8GEUy^+*F&0^bf zSLjFK;CU*&R*zST>;fN>$`QHlDuo*S=X6a<}rtRMx6H0hkSqboII0$SR5kNF4L1C&MT&!k3gtAc+=@{3MT z3lG|8{T@@USMdFP1^Cz&Gve(2V2)x;%Sgufb*C}R$WCX>#uCvRw!mucgL zLZhh=l`;W-hooH3rIY?fg{V+dVSX0p*C#?tDauK8EMBhTKcosD*`3MLd&(#cGooWJ z;HjZeZE zL6z->@HUIOUrUTzVQz`GC9KW4l|y2LYHFN#sevBEmL!w$G#Hsg!-VffQ|ksSupD|^ z-bnG8x#PgTXtBlOlJ1m68=gso;`e1x1o5`GgMPu-&xGW*pd9XD+n=SZ+-)dPFjvH)Qt?b1Q znfM@y4Jo6_g1e^N5z$^4ggUnRn)dRb^WfKH=`YI#3{_RU;o2ut8?YT|bF#8VZ>eGw z$o>|1k0IE`qhzZKAs;ige>x*CpL34^8tep`tG?;Xm480AXC)n)CKr@pljMyC6Tv^_ zsZuY-5pL63d20x|7L3ze7#_FyF(n52$?TrOepU1#>kz8^yF6YNd7GF<&n2pNQV_6v zLhX9!p$*GEMK{+NR!cOkW+he$JF6&2ByZfr{SqXvm7x2F!$MfPoiWI z&9CP_TvyDRF~nxqY!|6cKn2p=5m8EsEnB-&uM)!bmQ0!u+SLANR(s^TY<3si`=a5U zqrhoERCPLfs=g1hqqCp5^jEc>>%H{wy4SsQFK6hq(*S4ejQ`$7FLDv_P2Lju$TtG6 z020WGg~>3M4fxm3*SCmABc2AMBq25f1q zc^r7!Sja5yV^}^JQ(`cMV_-sFQ;hCmL0kw#ba8emHYE%R5%X^~t;pQunaD z(V7>I z>SkT!y769Il4^(yUI`>U05g*)BY=rHrO*>h&^$6^>k8J1L0E*1ol0~k7KcoLKn z5(^ny5Lq(h=OhyG)4HyXd`Xv&M4?J16wG-Nlzn)Xl$namPvGn z%oO_a6t_pd+v*jreNnKurXCz9ZS@*?@DE9vlc)q}YEVo>*2+4Y?e5c_a^@SI5tBiZ zIxJymDVwg}MI_06j9f2K793prw$^SdAstYw&9da5co3Lu%?siPj>ForRpwTGRTTVw zjh^0Tm$(!~gEYw;-8bLq8CBkLYt9SkTW}1fJ_bDawopAX~rM)3Z)OKWP z^L{4KGM)aaYq#oJUWMPyn-^Gt1N(_%oPq!KLfn>%8y$r~CDB_b;2<|Shosivsk2v zSC8}>6i_}z_NwB!Y;2p=XMXcMpMe*w0}0YV?~xBYqKD^U#+Ke#uu)y>fUg(1Y)rE) z(u{++K%pEFLIwZvR$g?u^Suz0p2>j@X;N?On<;fkt}iv+_hHu zg$cg1y^YwK*46s?aSh*e4HK3so-F*Nfe;gb)Mmd#!Mw&5Qq~p4&3CH7e`XXO>}(G6 z#$Ngf3=~)CkU^q5{$X1P#+j>K&Zw^pyqxRy_c*mlrJJD7Ps<{)!BW3VF_9Q^@nM1; zCXlx-krMR?aL~R=#}*=koS7)$_t}UE%zGuLdj9U?yyy%r{cU09;UZR|C38^NO+)m| zKQQf!2HgiT(+w3BGM{d;(v7qKD{F(GEQop-QjsyOLh}J2TW`$j9dulTXb?Zh+!>5i zcO2=Oo z->0Y2OJX)C=*!dv4cMp0(4+ghw*Aho0OfZ`-uXMB@lf6Ix4`x9m;JWA`a;uFe0M#| zJLKb`lEBUx@OYd|&(T|ClaP@%h0b%%JnFg*Ow0VNNxVTDv3OyLJ!o5vYW(fM6wmk< zTmJgYiE5G@+>3HxupYfkSa;%t4f&g34!ku!Jbgbk-d_eZH-^L*CHYS!_2CzWnFa_>#PHyAa5Xi+X+ptjEg#d3_Fhd~kNNcKUCNN0Xm2%H&5i22aGwLPI0o zBt;|p@6SH)giYA^KNJe{m;U9BBnsJq$NI=`^=w03axwS6JL%TM6)Si|FG Y?O^L-=_T)|24>0Ra=}vH$=8 diff --git a/docker-compose.override.yml b/docker-compose.override.yml new file mode 100644 index 0000000..f4f0a6c --- /dev/null +++ b/docker-compose.override.yml @@ -0,0 +1,14 @@ +version: '3' + +services: +###> doctrine/doctrine-bundle ### + database: + ports: + - "5432" +###< doctrine/doctrine-bundle ### + +###> symfony/mailer ### + mailer: + image: schickling/mailcatcher + ports: ["1025", "1080"] +###< symfony/mailer ### diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..1067b9c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +version: '3' + +services: +###> doctrine/doctrine-bundle ### + database: + image: postgres:${POSTGRES_VERSION:-15}-alpine + environment: + POSTGRES_DB: ${POSTGRES_DB:-app} + # You should definitely change the password in production + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!} + POSTGRES_USER: ${POSTGRES_USER:-app} + volumes: + - database_data:/var/lib/postgresql/data:rw + # You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data! + # - ./docker/db/data:/var/lib/postgresql/data:rw +###< doctrine/doctrine-bundle ### + +volumes: +###> doctrine/doctrine-bundle ### + database_data: +###< doctrine/doctrine-bundle ### diff --git a/example/environment/crontab b/example/environment/crontab deleted file mode 100644 index 136ec32..0000000 --- a/example/environment/crontab +++ /dev/null @@ -1,10 +0,0 @@ -@reboot searchd -@reboot indexer --all --rotate - -* * * * * indexer magnet --rotate > /dev/null 2>&1 - -* * * * * /usr/bin/php /YGGtracker/src/crontab/scrape.php > /dev/null 2>&1 -* * * * * /usr/bin/php /YGGtracker/src/crontab/export/push.php > /dev/null 2>&1 -0 5 * * * /usr/bin/php /YGGtracker/src/crontab/import/feed.php > /dev/null 2>&1 -0 0 * * * /usr/bin/php /YGGtracker/src/crontab/export/feed.php > /dev/null 2>&1 -0 0 * * * /usr/bin/php /YGGtracker/src/crontab/sitemap.php > /dev/null 2>&1 \ No newline at end of file diff --git a/example/environment/nginx b/example/environment/nginx deleted file mode 100644 index c5a243f..0000000 --- a/example/environment/nginx +++ /dev/null @@ -1,29 +0,0 @@ -server { - listen [::]:80 default; - - allow 0200::/7; - deny all; - - root /var/www/html; - - index index.html index.htm index.nginx-debian.html index.php; - - server_name _; - - location / { - try_files $uri $uri/ =404 @yggtracker; - } - - location ~ \.php$ { - include snippets/fastcgi-php.conf; - fastcgi_pass unix:/run/php/php8.1-fpm.sock; - } - - location ~ /\. { - deny all; - } - - location @yggtracker { - rewrite ^/(.*)$ /index.php?$1 last; - } -} \ No newline at end of file diff --git a/example/environment/sphinx.conf b/example/environment/sphinx.conf deleted file mode 100644 index b67c6a4..0000000 --- a/example/environment/sphinx.conf +++ /dev/null @@ -1,71 +0,0 @@ -source yggtracker -{ - type = mysql - - sql_port = 3306 - sql_host = localhost - sql_user = - sql_pass = - sql_db = -} - -source magnet : yggtracker -{ - sql_query = \ - SELECT `magnet`.`timeAdded`, \ - `magnet`.`timeUpdated`, \ - `magnet`.`magnetId`, \ - `magnet`.`title`, \ - `magnet`.`preview`, \ - `magnet`.`description`, \ - `magnet`.`dn`, \ - (SELECT GROUP_CONCAT(DISTINCT `infoHash`.`value`) \ - FROM `infoHash` \ - JOIN `magnetToInfoHash` ON (`magnetToInfoHash`.`magnetId` = `magnet`.`magnetId`) \ - WHERE `infoHash`.`infoHashId` = `magnetToInfoHash`.`infoHashId`) AS `infoHash`, \ - (SELECT GROUP_CONCAT(DISTINCT `keywordTopic`.`value`) \ - FROM `keywordTopic` \ - JOIN `magnetToKeywordTopic` ON (`magnetToKeywordTopic`.`magnetId` = `magnet`.`magnetId`) \ - WHERE `keywordTopic`.`keywordTopicId` = `magnetToKeywordTopic`.`keywordTopicId`) AS `keywords`, \ - (SELECT GROUP_CONCAT(DISTINCT `magnetComment`.`value`) \ - FROM `magnetComment` \ - WHERE `magnetComment`.`magnetId` = `magnet`.`magnetId`) AS `comments` \ - FROM `magnet`\ - - sql_attr_uint = magnetId -} - -index magnet -{ - source = magnet - path = /var/lib/sphinxsearch/data/magnet - - morphology = stem_cz, stem_ar, stem_enru - - min_word_len = 2 - min_prefix_len = 2 - - html_strip = 1 - - index_exact_words = 1 -} - -indexer -{ - mem_limit = 256M -} - -searchd -{ - listen = 127.0.0.1:9306:mysql41 - log = /var/log/sphinxsearch/searchd.log - query_log = /var/log/sphinxsearch/query.log - pid_file = /run/sphinxsearch/searchd.pid - binlog_path = /var/lib/sphinxsearch/data - read_timeout = 5 - max_children = 30 - seamless_rotate = 1 - preopen_indexes = 1 - unlink_old = 1 - workers = threads # for RT to work -} \ No newline at end of file diff --git a/src/storage/log/index.html b/migrations/.gitignore similarity index 100% rename from src/storage/log/index.html rename to migrations/.gitignore diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..6c4bfed --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + tests + + + + + + src + + + + + + + + + + diff --git a/src/public/assets/theme/default/css/common.css b/public/asset/default/css/common.css similarity index 100% rename from src/public/assets/theme/default/css/common.css rename to public/asset/default/css/common.css diff --git a/src/public/assets/theme/default/css/framework.css b/public/asset/default/css/framework.css similarity index 88% rename from src/public/assets/theme/default/css/framework.css rename to public/asset/default/css/framework.css index ea13706..65e4289 100644 --- a/src/public/assets/theme/default/css/framework.css +++ b/public/asset/default/css/framework.css @@ -122,19 +122,19 @@ a.label-green:hover { vertical-align: middle; } -.top--2 { +.top--2-px { top: -2px; } -.top-2 { +.top-2-px { top: 2px; } -.line-height-26 { +.line-height-26-px { line-height: 26px; } -.border-radius-3 { +.border-radius-3-px { border-radius: 3px; } @@ -227,138 +227,138 @@ a:visited.background-color-hover-night-light:hover { padding-right: 0; } -.padding-4 { +.padding-4-px { padding: 4px; } -.padding-t-4 { +.padding-t-4-px { padding-top: 4px; } -.padding-y-4 { +.padding-y-4-px { padding-top: 4px; padding-bottom: 4px; } -.padding-x-4 { +.padding-x-4-px { padding-left: 4px; padding-right: 4px; } -.padding-x-8 { +.padding-x-8-px { padding-left: 8px; padding-right: 8px; } -.padding-y-6 { +.padding-y-6-px { padding-top: 6px; padding-bottom: 6px; } -.padding-8 { +.padding-8-px { padding: 8px; } -.padding-t-8 { +.padding-t-8-px { padding-top: 8px; } -.padding-b-8 { +.padding-b-8-px { padding-bottom: 8px; } -.padding-y-8 { +.padding-y-8-px { padding-top: 8px; padding-bottom: 8px; } -.padding-y-12 { +.padding-y-12-px { padding-top: 12px; padding-bottom: 12px; } -.padding-b-16 { +.padding-b-16-px { padding-bottom: 16px; } -.padding-t-16 { +.padding-t-16-px { padding-top: 16px; } -.padding-y-16 { +.padding-y-16-px { padding-top: 16px; padding-bottom: 16px; } -.padding-x-16 { +.padding-x-16-px { padding-left: 16px; padding-right: 16px; } -.padding-16 { +.padding-16-px { padding: 16px; } -.margin-l-4 { +.margin-l-4-px { margin-left: 4px; } -.margin-l-8 { +.margin-l-8-px { margin-left: 8px; } -.margin-l-16 { +.margin-l-16-px { margin-left: 16px; } -.margin-x-4 { +.margin-x-4-px { margin-left: 4px; margin-right: 4px; } -.margin-r-4 { +.margin-r-4-px { margin-right: 4px; } -.margin-r-8 { +.margin-r-8-px { margin-right: 8px; } -.margin-l-12 { +.margin-l-12-px { margin-left: 12px; } -.margin-l--196 { +.margin-l--196-px { margin-left: -196px; } -.margin-y-8 { +.margin-y-8-px { margin-top: 8px; margin-bottom: 8px; } -.margin-t-8 { +.margin-t-8-px { margin-top: 8px; } -.margin-b-8 { +.margin-b-8-px { margin-bottom: 8px; } -.margin-y-16 { +.margin-y-16-px { margin-top: 16px; margin-bottom: 16px; } -.margin-t-16 { +.margin-t-16-px { margin-top: 16px; } -.margin-b-16 { +.margin-b-16-px { margin-bottom: 16px; } -.margin-b-24 { +.margin-b-24-px { margin-bottom: 24px; } @@ -410,10 +410,6 @@ a:visited.background-color-hover-night-light:hover { width: 80%; } -.width-13px { - width: 13px; -} - .width-180-px { width: 180px; } diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..9982c21 --- /dev/null +++ b/public/index.php @@ -0,0 +1,9 @@ +render('default/home/index.html.twig'); + } +} \ No newline at end of file diff --git a/src/Controller/PageController.php b/src/Controller/PageController.php new file mode 100644 index 0000000..7c45a43 --- /dev/null +++ b/src/Controller/PageController.php @@ -0,0 +1,67 @@ +render('default/page/submit.html.twig', [ + // @TODO + ]); + } + + #[Route( + '/{_locale}/page/stars', + name: 'page_stars' + )] + public function stars(): Response + { + // @TODO + } + + #[Route( + '/{_locale}/page/views', + name: 'page_views' + )] + public function views(): Response + { + // @TODO + } + + #[Route( + '/{_locale}/page/downloads', + name: 'page_downloads' + )] + public function downloads(): Response + { + // @TODO + } + + #[Route( + '/{_locale}/page/comments', + name: 'page_comments' + )] + public function comments(): Response + { + // @TODO + } + + #[Route( + '/{_locale}/page/editions', + name: 'page_editions' + )] + public function editions(): Response + { + // @TODO + } +} \ No newline at end of file diff --git a/src/Controller/ProfileController.php b/src/Controller/ProfileController.php new file mode 100644 index 0000000..c8a3b80 --- /dev/null +++ b/src/Controller/ProfileController.php @@ -0,0 +1,76 @@ +render( + 'default/profile/index.html.twig', + [ + 'user' => $user->init($request->getClientIp()) + ] + ); + } + + #[Route( + '/{_locale}/profile/setting', + name: 'profile_setting' + )] + public function setting(): Response + { + // @TODO + return $this->render( + 'default/profile/setting.html.twig' + ); + } + + public function module(string $route = ''): Response + { + return $this->render( + 'default/profile/module.html.twig', + [ + 'route' => $route, + 'stars' => 0, + 'views' => 0, + 'comments' => 0, + 'downloads' => 0, + 'editions' => 0, + 'identicon' => $this->_getIdenticon( + '@TODO', + 17, + [ + 'backgroundColor' => 'rgba(255, 255, 255, 0)', + ] + ) + ] + ); + } + + private function _getIdenticon( + mixed $id, + int $size, + array $style, + string $format = 'webp') : string + { + $identicon = new \Jdenticon\Identicon(); + + $identicon->setValue($id); + $identicon->setSize($size); + $identicon->setStyle($style); + + return $identicon->getImageDataUri($format); + } +} \ No newline at end of file diff --git a/src/Controller/SearchController.php b/src/Controller/SearchController.php new file mode 100644 index 0000000..7fea8a6 --- /dev/null +++ b/src/Controller/SearchController.php @@ -0,0 +1,31 @@ +query->get('query'); + + return $this->render('default/search/index.html.twig', [ + 'query' => $query + ]); + } + + public function module(string $query = ''): Response + { + return $this->render('default/search/module.html.twig', [ + 'query' => $query, + ]); + } +} \ No newline at end of file diff --git a/src/Entity/.gitignore b/src/Entity/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/src/Entity/Page.php b/src/Entity/Page.php new file mode 100644 index 0000000..f7f25c8 --- /dev/null +++ b/src/Entity/Page.php @@ -0,0 +1,27 @@ +id; + } + + public function setId(string $id): static + { + $this->id = $id; + + return $this; + } +} diff --git a/src/Entity/User.php b/src/Entity/User.php new file mode 100644 index 0000000..cf631a7 --- /dev/null +++ b/src/Entity/User.php @@ -0,0 +1,147 @@ +id; + } + + public function setId(string $id): static + { + $this->id = $id; + + return $this; + } + + public function getAddress(): ?string + { + return $this->address; + } + + public function setAddress(string $address): static + { + $this->address = $address; + + return $this; + } + + public function getAdded(): ?int + { + return $this->added; + } + + public function setAdded(int $added): static + { + $this->added = $added; + + return $this; + } + + public function getUpdated(): ?int + { + return $this->updated; + } + + public function setUpdated(int $updated): static + { + $this->updated = $updated; + + return $this; + } + + public function getVisited(): ?int + { + return $this->visited; + } + + public function setVisited(int $visited): static + { + $this->visited = $visited; + + return $this; + } + + public function isPublic(): ?bool + { + return $this->public; + } + + public function setPublic(bool $public): static + { + $this->public = $public; + + return $this; + } + + public function isModerator(): ?bool + { + return $this->moderator; + } + + public function setModerator(bool $moderator): static + { + $this->moderator = $moderator; + + return $this; + } + + public function isApproved(): ?bool + { + return $this->approved; + } + + public function setApproved(bool $approved): static + { + $this->approved = $approved; + + return $this; + } + + public function isStatus(): ?bool + { + return $this->status; + } + + public function setStatus(bool $status): static + { + $this->status = $status; + + return $this; + } +} diff --git a/src/Kernel.php b/src/Kernel.php new file mode 100644 index 0000000..779cd1f --- /dev/null +++ b/src/Kernel.php @@ -0,0 +1,11 @@ + + * + * @method Page|null find($id, $lockMode = null, $lockVersion = null) + * @method Page|null findOneBy(array $criteria, array $orderBy = null) + * @method Page[] findAll() + * @method Page[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + */ +class PageRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Page::class); + } + +// /** +// * @return Page[] Returns an array of Page objects +// */ +// public function findByExampleField($value): array +// { +// return $this->createQueryBuilder('p') +// ->andWhere('p.exampleField = :val') +// ->setParameter('val', $value) +// ->orderBy('p.id', 'ASC') +// ->setMaxResults(10) +// ->getQuery() +// ->getResult() +// ; +// } + +// public function findOneBySomeField($value): ?Page +// { +// return $this->createQueryBuilder('p') +// ->andWhere('p.exampleField = :val') +// ->setParameter('val', $value) +// ->getQuery() +// ->getOneOrNullResult() +// ; +// } +} diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php new file mode 100644 index 0000000..3767526 --- /dev/null +++ b/src/Repository/UserRepository.php @@ -0,0 +1,48 @@ + + * + * @method User|null find($id, $lockMode = null, $lockVersion = null) + * @method User|null findOneBy(array $criteria, array $orderBy = null) + * @method User[] findAll() + * @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + */ +class UserRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, User::class); + } + +// /** +// * @return User[] Returns an array of User objects +// */ +// public function findByExampleField($value): array +// { +// return $this->createQueryBuilder('u') +// ->andWhere('u.exampleField = :val') +// ->setParameter('val', $value) +// ->orderBy('u.id', 'ASC') +// ->setMaxResults(10) +// ->getQuery() +// ->getResult() +// ; +// } + +// public function findOneBySomeField($value): ?User +// { +// return $this->createQueryBuilder('u') +// ->andWhere('u.exampleField = :val') +// ->setParameter('val', $value) +// ->getQuery() +// ->getOneOrNullResult() +// ; +// } +} diff --git a/src/Service/User.php b/src/Service/User.php new file mode 100644 index 0000000..98890e0 --- /dev/null +++ b/src/Service/User.php @@ -0,0 +1,12 @@ +_database = $database; - $this->_validator = $validator; - $this->_website = $website; - $this->_session = $session; - } - - private function _initUser(string $address) - { - $error = []; - if (!$this->_validator->host($address, $error)) - { - $this->_response( - sprintf( - _('Error - %s'), - $this->_website->getName() - ), - _('406'), - $error, - 406 - ); - } - - try - { - $this->_database->beginTransaction(); - - $user = $this->_database->getUser( - $this->_database->initUserId( - $address, - $this->_website->getDefaultUserStatus(), - $this->_website->getDefaultUserApproved(), - time() - ) - ); - - $this->_database->commit(); - } - - catch (Exception $error) - { - $this->_database->rollback(); - - $this->_response( - sprintf( - _('Error - %s'), - $this->_website->getName() - ), - _('500'), - $error, - 500 - ); - } - - // Access denied - if (!$user->status) - { - $this->_response( - sprintf( - _('Error - %s'), - $this->_website->getName() - ), - _('403'), - _('Access denied'), - 403 - ); - } - } - - public function render() - { - $user = $this->_initUser( - $this->_session->getAddress() - ); - - $page = isset($_GET['page']) ? (int) $_GET['page'] : 1; - - $pages = []; - - require_once __DIR__ . '/module/pagination.php'; - - $appControllerModulePagination = new appControllerModulePagination(); - - require_once __DIR__ . '/module/head.php'; - - $appControllerModuleHead = new AppControllerModuleHead( - $this->_website->getUrl(), - $page > 1 ? - sprintf( - _('Page %s - BitTorrent Registry for Yggdrasil - %s'), - $page, - $this->_website->getName() - ) : - sprintf( - _('%s - BitTorrent Registry for Yggdrasil'), - $this->_website->getName() - ), - [ - [ - 'rel' => 'stylesheet', - 'type' => 'text/css', - 'href' => sprintf( - 'assets/theme/default/css/common.css?%s', - CSS_VERSION - ), - ], - [ - 'rel' => 'stylesheet', - 'type' => 'text/css', - 'href' => sprintf( - 'assets/theme/default/css/framework.css?%s', - CSS_VERSION - ), - ], - ] - ); - - require_once __DIR__ . '/module/profile.php'; - - $appControllerModuleProfile = new AppControllerModuleProfile( - $this->_database, - $this->_website, - $this->_session - ); - - require_once __DIR__ . '/module/header.php'; - - $appControllerModuleHeader = new AppControllerModuleHeader(); - - require_once __DIR__ . '/module/footer.php'; - - $appControllerModuleFooter = new AppControllerModuleFooter(); - - include __DIR__ . '/../view/theme/default/index.phtml'; - } -} \ No newline at end of file diff --git a/src/app/controller/module/footer.php b/src/app/controller/module/footer.php deleted file mode 100644 index a512e0e..0000000 --- a/src/app/controller/module/footer.php +++ /dev/null @@ -1,13 +0,0 @@ -api->export; - - include __DIR__ . '../../../view/theme/default/module/footer.phtml'; - } -} \ No newline at end of file diff --git a/src/app/controller/module/head.php b/src/app/controller/module/head.php deleted file mode 100644 index 781873b..0000000 --- a/src/app/controller/module/head.php +++ /dev/null @@ -1,54 +0,0 @@ -setBase($base); - $this->setTitle($title); - - foreach ($links as $link) - { - $this->addLink( - $link['rel'], - $link['type'], - $link['href'], - ); - } - } - - public function setBase(string $base) : void - { - $this->_base = $base; - } - - public function setTitle(string $title) : void - { - $this->_title = $title; - } - - public function addLink(string $rel, string $type, string $href) : void - { - $this->_links[] = (object) - [ - 'rel' => $rel, - 'type' => $type, - 'href' => $href, - ]; - } - - public function render() - { - $base = $this->_base; - - $links = $this->_links; - - $title = htmlentities($this->_title); - - include __DIR__ . '../../../view/theme/default/module/head.phtml'; - } -} \ No newline at end of file diff --git a/src/app/controller/module/header.php b/src/app/controller/module/header.php deleted file mode 100644 index 293a268..0000000 --- a/src/app/controller/module/header.php +++ /dev/null @@ -1,19 +0,0 @@ -YGG', - Environment::config('website')->name - ); - - require_once __DIR__ . '/search.php'; - - $appControllerModuleSearch = new AppControllerModuleSearch(); - - include __DIR__ . '../../../view/theme/default/module/header.phtml'; - } -} \ No newline at end of file diff --git a/src/app/controller/module/page.php b/src/app/controller/module/page.php deleted file mode 100644 index 036a6e7..0000000 --- a/src/app/controller/module/page.php +++ /dev/null @@ -1,9 +0,0 @@ - $limit) - { - parse_str($url, $query); - - $pagination->page = isset($query['total']) ? (int) $query['total'] : 1; - $pagination->pages = ceil($total / $limit); - - // Previous - if ($page > 1) - { - $query['page'] = $page - 1; - - $pagination->back = sprintf('%s', WEBSITE_URL, http_build_query($query)); - } - - else - { - $pagination->back = false; - } - - // Next - if ($page < ceil($total / $limit)) - { - $query['page'] = $page + 1; - - $pagination->next = sprintf('%s', WEBSITE_URL, http_build_query($query)); - } - - else - { - $pagination->next = false; - } - - // Render - } - } -} \ No newline at end of file diff --git a/src/app/controller/module/profile.php b/src/app/controller/module/profile.php deleted file mode 100644 index 0d82acc..0000000 --- a/src/app/controller/module/profile.php +++ /dev/null @@ -1,54 +0,0 @@ -_database = $database; - $this->_website = $website; - $this->_session = $session; - } - - public function render() - { - $route = isset($_GET['_route_']) ? (string) $_GET['_route_'] : ''; - - $user = $this->_database->getUser( - $this->_database->initUserId( - $this->_session->getAddress(), - $this->_website->getDefaultUserStatus(), - $this->_website->getDefaultUserApproved(), - time() - ) - ); - - $stars = $this->_database->findUserPageStarsDistinctTotalByValue($user->userId, true); - $views = $this->_database->findUserPageViewsDistinctTotal($user->userId); - $downloads = 0; // @TODO $this->_database->findUserPageDownloadsDistinctTotal($user->userId); - $comments = $this->_database->findUserPageCommentsDistinctTotal($user->userId); - $editions = 0; // @TODO $this->_database->findUserPageEditionsDistinctTotal($user->userId); - - $address = $user->address; - - $icon = new Jdenticon\Identicon(); - - $icon->setValue($user->address); - $icon->setSize(16); - $icon->setStyle( - [ - 'backgroundColor' => 'rgba(255, 255, 255, 0)', - ] - ); - - $identicon = $icon->getImageDataUri('webp'); - - include __DIR__ . '../../../view/theme/default/module/profile.phtml'; - } -} \ No newline at end of file diff --git a/src/app/controller/module/search.php b/src/app/controller/module/search.php deleted file mode 100644 index ff1017f..0000000 --- a/src/app/controller/module/search.php +++ /dev/null @@ -1,24 +0,0 @@ - $value) - { - $locales[$key] = (object) - [ - 'key' => $key, - 'value' => $value[0], - 'active' => $key === $locale // false !== stripos($_SERVER['HTTP_ACCEPT_LANGUAGE'], $key) ? true : false, - ]; - } - - include __DIR__ . '../../../view/theme/default/module/search.phtml'; - } -} \ No newline at end of file diff --git a/src/app/controller/page.php b/src/app/controller/page.php deleted file mode 100644 index a84c09c..0000000 --- a/src/app/controller/page.php +++ /dev/null @@ -1,428 +0,0 @@ -_database = $database; - $this->_validator = $validator; - $this->_locale = $locale; - $this->_website = $website; - $this->_session = $session; - $this->_request = $request; - } - - private function _response(string $title, string $h1, mixed $data, int $code = 200) - { - require_once __DIR__ . '/response.php'; - - if (is_array($data)) - { - $data = implode('
', $data); - } - - $appControllerResponse = new AppControllerResponse( - $title, - $h1, - $data, - $code - ); - - $appControllerResponse->render(); - - exit; - } - - private function _initUser(string $address) - { - $error = []; - if (!$this->_validator->host($address, $error)) - { - $this->_response( - sprintf( - _('Error - %s'), - $this->_website->getName() - ), - _('406'), - $error, - 406 - ); - } - - try - { - $this->_database->beginTransaction(); - - $user = $this->_database->getUser( - $this->_database->initUserId( - $address, - $this->_website->getDefaultUserStatus(), - $this->_website->getDefaultUserApproved(), - time() - ) - ); - - $this->_database->commit(); - } - - catch (Exception $error) - { - $this->_database->rollback(); - - $this->_response( - sprintf( - _('Error - %s'), - $this->_website->getName() - ), - _('500'), - $error, - 500 - ); - } - - // Access denied - if (!$user->status) - { - $this->_response( - sprintf( - _('Error - %s'), - $this->_website->getName() - ), - _('403'), - _('Access denied'), - 403 - ); - } - } - - private function _initLocale(string $value) - { - if (!$locale = $this->_database->findLocale($value)) - { - $locale = $this->_database->getLocale( - $this->_database->addLocale( - $value - ) - ); - } - - return $locale; - } - - private function _initPage(int $pageId = 0) - { - if (!$page = $this->_database->getPage($pageId)) - { - $page = $this->_database->getPage( - $this->_database->addPage( - time() - ) - ); - } - - return $page; - } - - private function _initText(string $value, string $mime = 'text/plain') - { - if (!$text = $this->_database->findText($mime, md5($value))) - { - $text = $this->_database->getText( - $this->_database->addText( - $mime, - md5($value), - $value, - time() - ) - ); - } - - return $text; - } - - private function _commitPageTitle(int $pageId, int $userId, int $localeId, string $text, string $mime = 'text/plain') - { - $textId = $this->_initText( - $text, - $mime - )->textId; - - if (!$this->_database->findPageTitleLatest($pageId, - $userId, - $localeId, - $textId)) - { - $this->_database->addPageTitle( - $pageId, - $userId, - $localeId, - $textId, - time() - ); - } - } - - public function renderFormSubmit() - { - // Init user - $user = $this->_initUser( - $this->_session->getAddress() - ); - - // Init page - if ($this->_request->get('pageId')) - { - $page = $this->_initPage( - (int) $this->_request->get('pageId') - ); - } - - else if ($this->_request->post('pageId')) - { - $page = $this->_initPage( - (int) $this->_request->post('pageId') - ); - } - - else - { - $page = $this->_initPage(); - } - - // Init locale - if ($this->_locale->codeExists($this->_request->get('locale'))) - { - $localeCode = (int) $this->_request->get('locale'); - } - - else if ($this->_locale->codeExists($this->_request->post('locale'))) - { - $localeCode = (int) $this->_request->post('locale'); - } - - else - { - $localeCode = $this->_website->getDefaultLocale(); - - if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) // @TODO environment - { - foreach ($this->_locale->getList() as $value) - { - if (false !== stripos($_SERVER['HTTP_ACCEPT_LANGUAGE'], $value->code)) - { - $localeCode = $value->code; - break; - } - } - } - } - - $locale = $this->_initLocale($localeCode); - - // Init form - $form = (object) - [ - 'pageId' => (object) - [ - 'error' => [], - 'type' => 'hidden', - 'attribute' => (object) - [ - 'value' => $page->pageId, - ] - ], - 'locale' => (object) - [ - 'error' => [], - 'type' => 'select', - 'options' => $this->_locale->getList(), - 'value' => $locale->value, - 'placeholder' => _('Page content language'), - ], - 'title' => (object) - [ - 'error' => [], - 'type' => 'text', - 'attribute' => (object) - [ - 'value' => null, - 'required' => $this->_validator->getPageTitleRequired(), - 'minlength' => $this->_validator->getPageTitleLengthMin(), - 'maxlength' => $this->_validator->getPageTitleLengthMax(), - 'placeholder' => sprintf( - _('Page subject (%s-%s chars)'), - number_format($this->_validator->getPageTitleLengthMin()), - number_format($this->_validator->getPageTitleLengthMax()) - ), - ] - ], - 'description' => (object) - [ - 'error' => [], - 'type' => 'textarea', - 'attribute' => (object) - [ - 'value' => null, - 'required' => $this->_validator->getPageDescriptionRequired(), - 'minlength' => $this->_validator->getPageDescriptionLengthMin(), - 'maxlength' => $this->_validator->getPageDescriptionLengthMax(), - 'placeholder' => sprintf( - _('Page description text (%s-%s chars)'), - number_format($this->_validator->getPageDescriptionLengthMin()), - number_format($this->_validator->getPageDescriptionLengthMax()) - ), - ] - ], - 'keywords' => (object) - [ - 'error' => [], - 'type' => 'textarea', - 'attribute' => (object) - [ - 'value' => null, - 'required' => $this->_validator->getPageKeywordsRequired(), - 'placeholder' => sprintf( - _('Page keywords (%s-%s total / %s-%s chars per item)'), - number_format($this->_validator->getPageKeywordsQuantityMin()), - number_format($this->_validator->getPageKeywordsQuantityMax()), - number_format($this->_validator->getPageKeywordLengthMin()), - number_format($this->_validator->getPageKeywordLengthMax()) - ), - ] - ], - 'sensitive' => (object) - [ - 'error' => [], - 'type' => 'checkbox', - 'attribute' => (object) - [ - 'value' => null, - 'placeholder' => _('Apply NSFW filters for this publication'), - ] - ] - ]; - - // Submit request - if ($this->_request->hasPost()) - { - /// Title - if ($title = $this->_request->post('title')) - { - $error = []; - - if (!$this->_validator->pageTitle($title, $error)) - { - $form->title->error[] = $error; - } - - else - { - $this->_commitPageTitle( - $page->pageId, - $user->userId, - $locale->localeId, - $title - ); - } - - $form->title->attribute->value = htmlentities($title); - } - - if (isset($_POST['description'])) - { - $error = []; - - if (!$this->_validator->pageDescription($_POST['description'], $error)) - { - $form->description->error[] = $error; - } - - $form->description->attribute->value = htmlentities($_POST['description']); - } - - if (isset($_POST['keywords'])) - { - $error = []; - - if (!$this->_validator->pageKeywords($_POST['keywords'], $error)) - { - $form->keywords->error[] = $error; - } - - $form->keywords->attribute->value = htmlentities($_POST['keywords']); - } - - if (isset($_POST['sensitive'])) - { - $form->sensitive->attribute->value = (bool) $_POST['sensitive']; - } - - // Request valid - if (empty($error)) - { - // @TODO redirect - } - } - - // Render template - require_once __DIR__ . '/module/head.php'; - - $appControllerModuleHead = new AppControllerModuleHead( - $this->_website->getUrl(), - sprintf( - _('Submit - %s'), - $this->_website->getName() - ), - [ - [ - 'rel' => 'stylesheet', - 'type' => 'text/css', - 'href' => sprintf( - 'assets/theme/default/css/common.css?%s', - CSS_VERSION - ), - ], - [ - 'rel' => 'stylesheet', - 'type' => 'text/css', - 'href' => sprintf( - 'assets/theme/default/css/framework.css?%s', - CSS_VERSION - ), - ], - ] - ); - - require_once __DIR__ . '/module/profile.php'; - - $appControllerModuleProfile = new AppControllerModuleProfile( - $this->_database, - $this->_website, - $this->_session - ); - - require_once __DIR__ . '/module/header.php'; - - $appControllerModuleHeader = new AppControllerModuleHeader(); - - require_once __DIR__ . '/module/footer.php'; - - $appControllerModuleFooter = new AppControllerModuleFooter(); - - include __DIR__ . '../../view/theme/default/page/form/submit.phtml'; - } -} \ No newline at end of file diff --git a/src/app/controller/response.php b/src/app/controller/response.php deleted file mode 100644 index eec6b53..0000000 --- a/src/app/controller/response.php +++ /dev/null @@ -1,65 +0,0 @@ -_title = $title; - $this->_h1 = $h1; - $this->_text = $text; - $this->_code = $code; - } - - public function render() - { - header( - sprintf( - 'HTTP/1.0 %s Not Found', - $this->_code - ) - ); - - $h1 = $this->_h1; - $text = $this->_text; - - require_once __DIR__ . '/module/head.php'; - - $appControllerModuleHead = new AppControllerModuleHead( - Environment::config('website')->url, - $this->_title, - [ - [ - 'rel' => 'stylesheet', - 'type' => 'text/css', - 'href' => sprintf( - 'assets/theme/default/css/common.css?%s', - CSS_VERSION - ), - ], - [ - 'rel' => 'stylesheet', - 'type' => 'text/css', - 'href' => sprintf( - 'assets/theme/default/css/framework.css?%s', - CSS_VERSION - ), - ], - ] - ); - - require_once __DIR__ . '/module/header.php'; - - $appControllerModuleHeader = new AppControllerModuleHeader(); - - require_once __DIR__ . '/module/footer.php'; - - $appControllerModuleFooter = new AppControllerModuleFooter(); - - include __DIR__ . '../../view/theme/default/response.phtml'; - } -} \ No newline at end of file diff --git a/src/app/controller/user.php b/src/app/controller/user.php deleted file mode 100644 index f356a2b..0000000 --- a/src/app/controller/user.php +++ /dev/null @@ -1,117 +0,0 @@ -_database = $database; - $this->_validator = $validator; - $this->_website = $website; - } - - private function _response(string $title, string $h1, mixed $data, int $code = 200) - { - require_once __DIR__ . '/response.php'; - - if (is_array($data)) - { - $data = implode('
', $data); - } - - $appControllerResponse = new AppControllerResponse( - $title, - $h1, - $data, - $code - ); - - $appControllerResponse->render(); - - exit; - } - - public function getIdenticon(int $size) - { - $icon = new Jdenticon\Identicon(); - - $icon->setValue($this->_user->public ? $this->_user->address : $this->_user->userId); - $icon->setSize($size); - $icon->setStyle( - [ - 'backgroundColor' => 'rgba(255, 255, 255, 0)', - ] - ); - - return $icon->getImageDataUri('webp'); - } - - public function getUser() - { - return $this->_user; - } - - public function getPublic() - { - return $this->_user->public; - } - - public function getAddress() - { - return $this->_user->address; - } - - public function findUserPageStarsDistinctTotalByValue(bool $value) : int - { - return $this->_database->findUserPageStarsDistinctTotal( - $this->_user->userId, - $value - ); - } - - public function findUserPageViewsDistinctTotal() : int - { - return $this->_database->findUserPageViewsDistinctTotal( - $this->_user->userId - ); - } - - public function findUserPageDownloadsDistinctTotal() : int - { - return $this->_database->findUserPageDownloadsDistinctTotal( - $this->_user->userId - ); - } - - public function findUserPageCommentsDistinctTotal() : int - { - return $this->_database->findUserPageCommentsDistinctTotal( - $this->_user->userId - ); - } - - public function findUserPageEditionsDistinctTotal() : int - { - return $this->_database->findUserPageEditionsDistinctTotal( - $this->_user->userId - ); - } - - public function updateUserPublic(bool $public, int $time) : int - { - return $this->_database->updateUserPublic( - $this->_user->userId, - $public, - $time - ); - } -} \ No newline at end of file diff --git a/src/app/model/database.php b/src/app/model/database.php deleted file mode 100644 index 9bf5a8e..0000000 --- a/src/app/model/database.php +++ /dev/null @@ -1,1866 +0,0 @@ -_db = new PDO( - 'mysql:dbname=' . $config->name . ';host=' . $config->host . ';port=' . $config->port . ';charset=utf8', - $config->user, - $config->password, - [ - PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8' - ] - ); - - $this->_db->setAttribute( - PDO::ATTR_ERRMODE, - PDO::ERRMODE_EXCEPTION - ); - - $this->_db->setAttribute( - PDO::ATTR_DEFAULT_FETCH_MODE, - PDO::FETCH_OBJ - ); - - $this->_db->setAttribute( - PDO::ATTR_TIMEOUT, - 600 - ); - - $this->_debug = (object) - [ - 'query' => (object) - [ - 'select' => (object) - [ - 'total' => 0 - ], - 'insert' => (object) - [ - 'total' => 0 - ], - 'update' => (object) - [ - 'total' => 0 - ], - 'delete' => (object) - [ - 'total' => 0 - ], - ] - ]; - } - - // Tools - public function beginTransaction() : void - { - $this->_db->beginTransaction(); - } - - public function commit() : void - { - $this->_db->commit(); - } - - public function rollBack() : void - { - $this->_db->rollBack(); - } - - public function getDebug() : object - { - return $this->_debug; - } - - // Locale - public function addLocale(string $value) : int - { - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `locale` SET `value` = ?'); - - $query->execute([$value]); - - return $this->_db->lastInsertId(); - } - - public function getLocale(int $localeId) - { - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `locale` WHERE `localeId` = ?'); - - $query->execute([$localeId]); - - return $query->fetch(); - } - - public function findLocale(string $value) - { - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `locale` WHERE `value` = ?'); - - $query->execute([$value]); - - return $query->fetch(); - } - - // Text - public function addText(string $mime, string $hash, string $value) : int - { - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `text` SET `mime` = ?, `hash` = ?, `value` = ?'); - - $query->execute([$mime, $hash, $value]); - - return $this->_db->lastInsertId(); - } - - public function getText(int $textId) - { - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `text` WHERE `textId` = ?'); - - $query->execute([$textId]); - - return $query->fetch(); - } - - public function findText(string $mime, string $hash) - { - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `text` WHERE `mime` = ? AND `hash` = ?'); - - $query->execute([$mime, $hash]); - - return $query->fetch(); - } - - // Page - public function addPage(int $timeAdded) : int - { - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `page` SET `timeAdded` = ?'); - - $query->execute([$timeAdded]); - - return $this->_db->lastInsertId(); - } - - public function getPage(int $pageId) - { - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `page` WHERE `pageId` = ?'); - - $query->execute([$pageId]); - - return $query->fetch(); - } - - // Scheme - public function addScheme(string $value) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `scheme` SET `value` = ?'); - - $query->execute([$value]); - - return $this->_db->lastInsertId(); - } - - public function getScheme(int $schemeId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `scheme` WHERE `schemeId` = ?'); - - $query->execute([$schemeId]); - - return $query->fetch(); - } - - public function findScheme(string $value) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `scheme` WHERE `value` = ?'); - - $query->execute([$value]); - - return $query->fetch(); - } - - public function initSchemeId(string $value) : int { - - if ($result = $this->findScheme($value)) { - - return $result->schemeId; - } - - return $this->addScheme($value); - } - - // Host - public function addHost(string $value) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `host` SET `value` = ?'); - - $query->execute([$value]); - - return $this->_db->lastInsertId(); - } - - public function getHost(int $hostId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `host` WHERE `hostId` = ?'); - - $query->execute([$hostId]); - - return $query->fetch(); - } - - public function findHost(string $value) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `host` WHERE `value` = ?'); - - $query->execute([$value]); - - return $query->fetch(); - } - - public function initHostId(string $value) : int { - - if ($result = $this->findHost($value)) { - - return $result->hostId; - } - - return $this->addHost($value); - } - - // Port - public function addPort(mixed $value) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `port` SET `value` = ?'); - - $query->execute([$value]); - - return $this->_db->lastInsertId(); - } - - public function getPort(int $portId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `port` WHERE `portId` = ?'); - - $query->execute([$portId]); - - return $query->fetch(); - } - - public function findPort(mixed $value) { - - $this->_debug->query->select->total++; - - if ($value) { - - $query = $this->_db->prepare('SELECT * FROM `port` WHERE `value` = ?'); - - $query->execute([$value]); - - } else { - - $query = $this->_db->query('SELECT * FROM `port` WHERE `value` IS NULL'); - } - - return $query->fetch(); - } - - public function initPortId(mixed $value) : int { - - if ($result = $this->findPort($value)) { - - return $result->portId; - } - - return $this->addPort($value); - } - - // URI - public function addUri(mixed $value) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `uri` SET `value` = ?'); - - $query->execute([$value]); - - return $this->_db->lastInsertId(); - } - - public function getUri(int $uriId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `uri` WHERE `uriId` = ?'); - - $query->execute([$uriId]); - - return $query->fetch(); - } - - public function findUri(mixed $value) { - - $this->_debug->query->select->total++; - - if ($value) { - - $query = $this->_db->prepare('SELECT * FROM `uri` WHERE `value` = ?'); - - $query->execute([$value]); - - } else { - - $query = $this->_db->query('SELECT * FROM `uri` WHERE `value` IS NULL'); - } - - return $query->fetch(); - } - - public function initUriId(mixed $value) : int { - - if ($result = $this->findUri($value)) { - - return $result->uriId; - } - - return $this->addUri($value); - } - - // Info Hash - public function addInfoHash(mixed $value, int $version) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `infoHash` SET `value` = ?, `version` = ?'); - - $query->execute([$value, $version]); - - return $this->_db->lastInsertId(); - } - - public function getInfoHash(int $infoHashId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `infoHash` WHERE `infoHashId` = ?'); - - $query->execute([$infoHashId]); - - return $query->fetch(); - } - - public function findInfoHash(string $value, int $version) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `infoHash` WHERE `value` = ? AND `version` = ?'); - - $query->execute([$value, $version]); - - return $query->fetch(); - } - - public function initInfoHashId(mixed $value, int $version) : int { - - if ($result = $this->findInfoHash($value, $version)) { - - return $result->infoHashId; - } - - return $this->addInfoHash($value, $version); - } - - // Address Tracker - public function addAddressTracker(int $schemeId, int $hostId, mixed $portId, mixed $uriId) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `addressTracker` SET `schemeId` = ?, `hostId` = ?, `portId` = ?, `uriId` = ?'); - - $query->execute([$schemeId, $hostId, $portId, $uriId]); - - return $this->_db->lastInsertId(); - } - - public function getAddressTracker(int $addressTrackerId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `addressTracker` WHERE `addressTrackerId` = ?'); - - $query->execute([$addressTrackerId]); - - return $query->fetch(); - } - - public function findAddressTracker(int $schemeId, int $hostId, mixed $portId, mixed $uriId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->query('SELECT * FROM `addressTracker` WHERE `schemeId` = ' . (int) $schemeId . ' - AND `hostId` = ' . (int) $hostId . ' - AND `portId` ' . ($portId ? ' = ' . (int) $portId : ' IS NULL ') . ' - AND `uriId` ' . ($uriId ? ' = ' . (int) $uriId : ' IS NULL ')); - - return $query->fetch(); - } - - public function initAddressTrackerId(int $schemeId, int $hostId, mixed $portId, mixed $uriId) : int { - - if ($result = $this->findAddressTracker($schemeId, $hostId, $portId, $uriId)) { - - return $result->addressTrackerId; - } - - return $this->addAddressTracker($schemeId, $hostId, $portId, $uriId); - } - - // Acceptable Source - public function addAcceptableSource(int $schemeId, int $hostId, mixed $portId, mixed $uriId) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `acceptableSource` SET `schemeId` = ?, `hostId` = ?, `portId` = ?, `uriId` = ?'); - - $query->execute([$schemeId, $hostId, $portId, $uriId]); - - return $this->_db->lastInsertId(); - } - - public function getAcceptableSource(int $acceptableSourceId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `acceptableSource` WHERE `acceptableSourceId` = ?'); - - $query->execute([$acceptableSourceId]); - - return $query->fetch(); - } - - public function findAcceptableSource(int $schemeId, int $hostId, mixed $portId, mixed $uriId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->query('SELECT * FROM `acceptableSource` WHERE `schemeId` = ' . (int) $schemeId . ' - AND `hostId` = ' . (int) $hostId . ' - AND `portId` ' . ($portId ? ' = ' . (int) $portId : ' IS NULL ') . ' - AND `uriId` ' . ($uriId ? ' = ' . (int) $uriId : ' IS NULL ')); - - return $query->fetch(); - } - - public function initAcceptableSourceId(int $schemeId, int $hostId, mixed $portId, mixed $uriId) : int { - - if ($result = $this->findAcceptableSource($schemeId, $hostId, $portId, $uriId)) { - - return $result->acceptableSourceId; - } - - return $this->addAcceptableSource($schemeId, $hostId, $portId, $uriId); - } - - // eXact Source - public function addExactSource(int $schemeId, int $hostId, mixed $portId, mixed $uriId) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `eXactSource` SET `schemeId` = ?, `hostId` = ?, `portId` = ?, `uriId` = ?'); - - $query->execute([$schemeId, $hostId, $portId, $uriId]); - - return $this->_db->lastInsertId(); - } - - public function getExactSource(int $eXactSourceId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `eXactSource` WHERE `eXactSourceId` = ?'); - - $query->execute([$eXactSourceId]); - - return $query->fetch(); - } - - public function findExactSource(int $schemeId, int $hostId, mixed $portId, mixed $uriId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->query('SELECT * FROM `eXactSource` WHERE `schemeId` = ' . (int) $schemeId . ' - AND `hostId` = ' . (int) $hostId . ' - AND `portId` ' . ($portId ? ' = ' . (int) $portId : ' IS NULL ') . ' - AND `uriId` ' . ($uriId ? ' = ' . (int) $uriId : ' IS NULL ')); - - return $query->fetch(); - } - - public function initExactSourceId(int $schemeId, int $hostId, mixed $portId, mixed $uriId) : int { - - if ($result = $this->findExactSource($schemeId, $hostId, $portId, $uriId)) { - - return $result->eXactSourceId; - } - - return $this->addExactSource($schemeId, $hostId, $portId, $uriId); - } - - // Keyword Topic - public function addKeywordTopic(string $value) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `keywordTopic` SET `value` = ?'); - - $query->execute([$value]); - - return $this->_db->lastInsertId(); - } - - public function findKeywordTopic(string $value) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `keywordTopic` WHERE `value` = ?'); - - $query->execute([$value]); - - return $query->fetch(); - } - - public function getKeywordTopic(int $keywordTopicId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `keywordTopic` WHERE `keywordTopicId` = ?'); - - $query->execute([$keywordTopicId]); - - return $query->fetch(); - } - - public function initKeywordTopicId(string $value) : int { - - if ($result = $this->findKeywordTopic($value)) { - - return $result->keywordTopicId; - } - - return $this->addKeywordTopic($value); - } - - // User - public function addUser(string $address, bool $status, bool $approved, $timeAdded) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `user` SET `address` = ?, `status` = ?, `approved` = ?, `timeAdded` = ?'); - - $query->execute([$address, (int) $status, (int) $approved, $timeAdded]); - - return $this->_db->lastInsertId(); - } - - public function getUser(int $userId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `user` WHERE `userId` = ?'); - - $query->execute([$userId]); - - return $query->fetch(); - } - - public function getUsers() { - - $this->_debug->query->select->total++; - - $query = $this->_db->query('SELECT * FROM `user`'); - - return $query->fetchAll(); - } - - public function getUsersTotal() : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `user`'); - - $query->execute(); - - return $query->fetch()->result; - } - - public function getUsersTotalByPublic(mixed $public) : int { - - $this->_debug->query->select->total++; - - if (is_null($public)) - { - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `user` WHERE `public` IS NULL'); - $query->execute(); - } - else - { - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `user` WHERE `public` = ?'); - $query->execute([(int) $public]); - } - - return $query->fetch()->result; - } - - public function findUserByAddress(string $address) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `user` WHERE `address` = ?'); - - $query->execute([$address]); - - return $query->fetch(); - } - - public function initUserId(string $address, bool $status, bool $approved, int $timeAdded) : int { - - if ($result = $this->findUserByAddress($address)) { - - return $result->userId; - } - - return $this->addUser($address, $status, $approved, $timeAdded); - } - - public function updateUserApproved(int $userId, mixed $approved, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `user` SET `approved` = ?, `timeUpdated` = ? WHERE `userId` = ?'); - - $query->execute([(int) $approved, $timeUpdated, $userId]); - - return $query->rowCount(); - } - - public function updateUserPublic(int $userId, bool $public, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `user` SET `public` = ?, `timeUpdated` = ? WHERE `userId` = ?'); - - $query->execute([(int) $public, $timeUpdated, $userId]); - - return $query->rowCount(); - } - - public function updateUserTimeAdded(int $userId, int $timeAdded) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `user` SET `timeAdded` = ? WHERE `userId` = ?'); - - $query->execute([$timeAdded, $userId]); - - return $query->rowCount(); - } - - public function updateUserTimeUpdated(int $userId, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `user` SET `timeUpdated` = ? WHERE `userId` = ?'); - - $query->execute([$timeUpdated, $userId]); - - return $query->rowCount(); - } - - public function findUserPageStarsDistinctTotalByValue(int $userId, bool $value) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(DISTINCT `pageId`) AS `result` FROM `pageStar` WHERE `userId` = ? AND `value` = ?'); - - $query->execute([$userId, (int) $value]); - - return $query->fetch()->result; - } - - public function findUserPageViewsDistinctTotal(int $userId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(DISTINCT `pageId`) AS `result` FROM `pageView` WHERE `userId` = ?'); - - $query->execute([$userId]); - - return $query->fetch()->result; - } - - public function findUserPageCommentsDistinctTotal(int $userId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(DISTINCT `pageId`) AS `result` FROM `pageComment` WHERE `userId` = ?'); - - $query->execute([$userId]); - - return $query->fetch()->result; - } - - public function findUserPageEditionsDistinctTotal(int $userId) : int { - - return 0; - - /* @TODO - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(DISTINCT `pageId`) AS `result` FROM `userPageEdition` WHERE `userId` = ?'); - - $query->execute([$userId]); - - return $query->fetch()->result; - */ - } - - // Magnet - public function addMagnet(int $userId, - int $xl, - string $dn, - string $linkSource, - bool $public, - bool $comments, - bool $sensitive, - bool $approved, - int $timeAdded, - mixed $timeUpdated = null) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `magnet` SET `userId` = ?, - `xl` = ?, - `dn` = ?, - `linkSource` = ?, - `public` = ?, - `comments` = ?, - `sensitive` = ?, - `approved` = ?, - `timeAdded` = ?, - `timeUpdated` = ?'); - - $query->execute( - [ - $userId, - $xl, - $dn, - $linkSource, - $public ? 1 : 0, - $comments ? 1 : 0, - $sensitive ? 1 : 0, - $approved ? 1 : 0, - $timeAdded, - $timeUpdated - ] - ); - - return $this->_db->lastInsertId(); - } - - public function getMagnet(int $magnetId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnet` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return $query->fetch(); - } - - public function getMagnets() { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnet`'); - - $query->execute(); - - return $query->fetchAll(); - } - - public function getMagnetsTotal() : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `magnet`'); - - $query->execute(); - - return $query->fetch()->result; - } - - public function findMagnet(int $userId, int $timeAdded) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnet` WHERE `userId` = ? AND `timeAdded` = ?'); - - $query->execute([$userId, $timeAdded]); - - return $query->fetch(); - } - - public function findMagnetsByUserId(int $userId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnet` WHERE `userId` = ?'); - - $query->execute([$userId]); - - return $query->fetchAll(); - } - - public function findMagnetsTotalByUserId(int $userId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `magnet` WHERE `userId` = ?'); - - $query->execute([$userId]); - - return $query->fetch()->result; - } - - public function getMagnetsTotalByUsersPublic(bool $public) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `magnet` - JOIN `user` ON (`user`.`userId` = `magnet`.`userId`) - WHERE `user`.`public` = ?'); - - $query->execute([(int) $public]); - - return $query->fetch()->result; - } - - public function updateMagnetXl(int $magnetId, int $xl, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnet` SET `xl` = ?, `timeUpdated` = ? WHERE `magnetId` = ?'); - - $query->execute([$xl, $timeUpdated, $magnetId]); - - return $query->rowCount(); - } - - public function updateMagnetDn(int $magnetId, string $dn, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnet` SET `dn` = ?, `timeUpdated` = ? WHERE `magnetId` = ?'); - - $query->execute([$dn, $timeUpdated, $magnetId]); - - return $query->rowCount(); - } - - public function updateMagnetTitle(int $magnetId, string $title, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnet` SET `title` = ?, `timeUpdated` = ? WHERE `magnetId` = ?'); - - $query->execute([$title, $timeUpdated, $magnetId]); - - return $query->rowCount(); - } - - public function updateMagnetPreview(int $magnetId, string $preview, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnet` SET `preview` = ?, `timeUpdated` = ? WHERE `magnetId` = ?'); - - $query->execute([$preview, $timeUpdated, $magnetId]); - - return $query->rowCount(); - } - - public function updateMagnetDescription(int $magnetId, string $description, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnet` SET `description` = ?, `timeUpdated` = ? WHERE `magnetId` = ?'); - - $query->execute([$description, $timeUpdated, $magnetId]); - - return $query->rowCount(); - } - - public function updateMagnetPublic(int $magnetId, bool $public, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnet` SET `public` = ?, `timeUpdated` = ? WHERE `magnetId` = ?'); - - $query->execute([(int) $public, $timeUpdated, $magnetId]); - - return $query->rowCount(); - } - - public function updateMagnetComments(int $magnetId, bool $comments, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnet` SET `comments` = ?, `timeUpdated` = ? WHERE `magnetId` = ?'); - - $query->execute([(int) $comments, $timeUpdated, $magnetId]); - - return $query->rowCount(); - } - - public function updateMagnetSensitive(int $magnetId, bool $sensitive, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnet` SET `sensitive` = ?, `timeUpdated` = ? WHERE `magnetId` = ?'); - - $query->execute([(int) $sensitive, $timeUpdated, $magnetId]); - - return $query->rowCount(); - } - - public function updateMagnetApproved(int $magnetId, bool $approved, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnet` SET `approved` = ?, `timeUpdated` = ? WHERE `magnetId` = ?'); - - $query->execute([(int) $approved, $timeUpdated, $magnetId]); - - return $query->rowCount(); - } - - public function updateMagnetTimeUpdated(int $magnetId, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnet` SET `timeUpdated` = ? WHERE `magnetId` = ?'); - - $query->execute([$timeUpdated, $magnetId]); - - return $query->rowCount(); - } - - public function updateMagnetTimeAdded(int $magnetId, int $timeAdded) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnet` SET `timeAdded` = ? WHERE `magnetId` = ?'); - - $query->execute([$timeAdded, $magnetId]); - - return $query->rowCount(); - } - - // Magnet to Info Hash - public function addMagnetToInfoHash(int $magnetId, int $infoHashId) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `magnetToInfoHash` SET `magnetId` = ?, `infoHashId` = ?'); - - $query->execute([$magnetId, $infoHashId]); - - return $this->_db->lastInsertId(); - } - - public function findMagnetToInfoHashByMagnetId(int $magnetId) - { - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetToInfoHash` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return $query->fetchAll(); - } - - // Magnet to AddressTracker - public function addMagnetToAddressTracker(int $magnetId, int $addressTrackerId) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `magnetToAddressTracker` SET `magnetId` = ?, `addressTrackerId` = ?'); - - $query->execute([$magnetId, $addressTrackerId]); - - return $this->_db->lastInsertId(); - } - - public function updateMagnetToAddressTrackerSeeders(int $magnetToAddressTrackerId, int $seeders, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnetToAddressTracker` SET `seeders` = ?, `timeUpdated` = ? WHERE `magnetToAddressTrackerId` = ?'); - - $query->execute([$seeders, $timeUpdated, $magnetToAddressTrackerId]); - - return $query->rowCount(); - } - - public function updateMagnetToAddressTrackerCompleted(int $magnetToAddressTrackerId, int $completed, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnetToAddressTracker` SET `completed` = ?, `timeUpdated` = ? WHERE `magnetToAddressTrackerId` = ?'); - - $query->execute([$completed, $timeUpdated, $magnetToAddressTrackerId]); - - return $query->rowCount(); - } - - public function updateMagnetToAddressTrackerLeechers(int $magnetToAddressTrackerId, int $leechers, int $timeUpdated) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnetToAddressTracker` SET `leechers` = ?, `timeUpdated` = ? WHERE `magnetToAddressTrackerId` = ?'); - - $query->execute([$leechers, $timeUpdated, $magnetToAddressTrackerId]); - - return $query->rowCount(); - } - - public function updateMagnetToAddressTrackerTimeOffline(int $magnetToAddressTrackerId, mixed $timeOffline) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnetToAddressTracker` SET `timeOffline` = ? WHERE `magnetToAddressTrackerId` = ?'); - - $query->execute([$timeOffline, $magnetToAddressTrackerId]); - - return $query->rowCount(); - } - - public function deleteMagnetToAddressTrackerByMagnetId(int $magnetId) : int { - - $this->_debug->query->delete->total++; - - $query = $this->_db->prepare('DELETE FROM `magnetToAddressTracker` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return $query->rowCount(); - } - - public function findMagnetToAddressTracker(int $magnetId, int $addressTrackerId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetToAddressTracker` WHERE `magnetId` = ? AND `addressTrackerId` = ?'); - - $query->execute([$magnetId, $addressTrackerId]); - - return $query->fetch(); - } - - public function findAddressTrackerByMagnetId(int $magnetId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetToAddressTracker` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return $query->fetchAll(); - } - - public function getMagnetToAddressTrackerScrapeQueue(int $limit) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetToAddressTracker` - - WHERE `timeOffline` IS NULL - - ORDER BY `timeUpdated` ASC, RAND() - - LIMIT ' . (int) $limit); - - $query->execute(); - - return $query->fetchAll(); - } - - public function resetMagnetToAddressTrackerTimeOfflineByTimeout(int $timeOffline) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnetToAddressTracker` SET `timeOffline` = NULL WHERE `timeOffline` < ?'); - - $query->execute( - [ - time() - $timeOffline - ] - ); - - return $query->rowCount(); - } - - public function initMagnetToAddressTrackerId(int $magnetId, int $addressTrackerId) : int { - - if ($result = $this->findMagnetToAddressTracker($magnetId, $addressTrackerId)) { - - return $result->magnetToAddressTrackerId; - } - - return $this->addMagnetToAddressTracker($magnetId, $addressTrackerId); - } - - public function getMagnetToAddressTrackerSeedersSumByMagnetId(int $magnetId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT SUM(`seeders`) AS `result` FROM `magnetToAddressTracker` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return (int) $query->fetch()->result; - } - - public function getMagnetToAddressTrackerCompletedSumByMagnetId(int $magnetId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT SUM(`completed`) AS `result` FROM `magnetToAddressTracker` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return (int) $query->fetch()->result; - } - - public function getMagnetToAddressTrackerLeechersSumByMagnetId(int $magnetId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT SUM(`leechers`) AS `result` FROM `magnetToAddressTracker` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return (int) $query->fetch()->result; - } - - public function getMagnetToAcceptableSourceTotalByMagnetId(int $magnetId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `magnetToAcceptableSource` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return (int) $query->fetch()->result; - } - - public function getMagnetToAddressTrackerSeedersSum() : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT SUM(`seeders`) AS `result` FROM `magnetToAddressTracker`'); - - $query->execute(); - - return (int) $query->fetch()->result; - } - - public function getMagnetToAddressTrackerCompletedSum() : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT SUM(`completed`) AS `result` FROM `magnetToAddressTracker`'); - - $query->execute(); - - return (int) $query->fetch()->result; - } - - public function getMagnetToAddressTrackerLeechersSum() : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT SUM(`leechers`) AS `result` FROM `magnetToAddressTracker`'); - - $query->execute(); - - return (int) $query->fetch()->result; - } - - // Magnet to AcceptableSource - public function addMagnetToAcceptableSource(int $magnetId, int $acceptableSourceId) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `magnetToAcceptableSource` SET `magnetId` = ?, `acceptableSourceId` = ?'); - - $query->execute([$magnetId, $acceptableSourceId]); - - return $this->_db->lastInsertId(); - } - - public function deleteMagnetToAcceptableSourceByMagnetId(int $magnetId) : int { - - $this->_debug->query->delete->total++; - - $query = $this->_db->prepare('DELETE FROM `magnetToAcceptableSource` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return $query->rowCount(); - } - - public function findMagnetToAcceptableSource(int $magnetId, int $acceptableSourceId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetToAcceptableSource` WHERE `magnetId` = ? AND `acceptableSourceId` = ?'); - - $query->execute([$magnetId, $acceptableSourceId]); - - return $query->fetch(); - } - - public function findAcceptableSourceByMagnetId(int $magnetId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetToAcceptableSource` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return $query->fetchAll(); - } - - public function initMagnetToAcceptableSourceId(int $magnetId, int $acceptableSourceId) : int { - - if ($result = $this->findMagnetToAcceptableSource($magnetId, $acceptableSourceId)) { - - return $result->magnetToAcceptableSourceId; - } - - return $this->addMagnetToAcceptableSource($magnetId, $acceptableSourceId); - } - - // Magnet to eXactSource - public function addMagnetToExactSource(int $magnetId, int $eXactSourceId) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `magnetToExactSource` SET `magnetId` = ?, `eXactSourceId` = ?'); - - $query->execute([$magnetId, $eXactSourceId]); - - return $this->_db->lastInsertId(); - } - - public function deleteMagnetToExactSourceByMagnetId(int $magnetId) : int { - - $this->_debug->query->delete->total++; - - $query = $this->_db->prepare('DELETE FROM `magnetToExactSource` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return $this->_db->lastInsertId(); - } - - public function findMagnetToExactSource(int $magnetId, int $eXactSourceId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetToExactSource` WHERE `magnetId` = ? AND `eXactSourceId` = ?'); - - $query->execute([$magnetId, $eXactSourceId]); - - return $query->fetch(); - } - - public function findExactSourceByMagnetId(int $magnetId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetToExactSource` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return $query->fetchAll(); - } - - public function initMagnetToExactSourceId(int $magnetId, int $eXactSourceId) : int { - - if ($result = $this->findMagnetToEXactSource($magnetId, $eXactSourceId)) { - - return $result->magnetToExactSourceId; - } - - return $this->addMagnetToEXactSource($magnetId, $eXactSourceId); - } - - // Magnet to KeywordTopic - public function addMagnetToKeywordTopic(int $magnetId, int $keywordTopicId) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `magnetToKeywordTopic` SET `magnetId` = ?, `keywordTopicId` = ?'); - - $query->execute([$magnetId, $keywordTopicId]); - - return $this->_db->lastInsertId(); - } - - public function deleteMagnetToKeywordTopicByMagnetId(int $magnetId) : int { - - $this->_debug->query->delete->total++; - - $query = $this->_db->prepare('DELETE FROM `magnetToKeywordTopic` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return $query->rowCount(); - } - - public function findMagnetToKeywordTopic(int $magnetId, int $keywordTopicId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetToKeywordTopic` WHERE `magnetId` = ? AND `keywordTopicId` = ?'); - - $query->execute([$magnetId, $keywordTopicId]); - - return $query->fetch(); - } - - public function findKeywordTopicByMagnetId(int $magnetId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetToKeywordTopic` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return $query->fetchAll(); - } - - public function initMagnetToKeywordTopicId(int $magnetId, int $keywordTopicId) : int { - - if ($result = $this->findMagnetToKeywordTopic($magnetId, $keywordTopicId)) { - - return $result->magnetToKeywordTopicId; - } - - return $this->addMagnetToKeywordTopic($magnetId, $keywordTopicId); - } - - // Magnet lock - public function addMagnetLock(int $magnetId, int $userId, int $timeAdded) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `magnetLock` SET `magnetId` = ?, `userId` = ?, `timeAdded` = ?'); - - $query->execute([$magnetId, $userId, $timeAdded]); - - return $this->_db->lastInsertId(); - } - - public function flushMagnetLock(int $magnetId) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('DELETE FROM `magnetLock` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return $query->rowCount(); - } - - public function findLastMagnetLock(int $magnetId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetLock` WHERE `magnetId` = ? ORDER BY `magnetLockId` DESC LIMIT 1'); - - $query->execute([$magnetId]); - - return $query->fetch(); - } - - // Magnet comment - public function addMagnetComment( int $magnetId, - int $userId, - mixed $magnetCommentIdParent, - string $value, - bool $approved, - bool $public, - int $timeAdded) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `magnetComment` SET `magnetId` = ?, - `userId` = ?, - `magnetCommentIdParent` = ?, - `value` = ?, - `approved` = ?, - `public` = ?, - `timeAdded` = ?'); - - $query->execute( - [ - $magnetId, - $userId, - $magnetCommentIdParent, - $value, - $approved, - $public, - $timeAdded - ] - ); - - return $this->_db->lastInsertId(); - } - - public function updateMagnetCommentPublic(int $magnetCommentId, mixed $public) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnetComment` SET `public` = ? WHERE `magnetCommentId` = ?'); - - $query->execute([(int) $public, $magnetCommentId]); - - return $query->rowCount(); - } - - public function updateMagnetCommentApproved(int $magnetCommentId, mixed $approved) : int { - - $this->_debug->query->update->total++; - - $query = $this->_db->prepare('UPDATE `magnetComment` SET `approved` = ? WHERE `magnetCommentId` = ?'); - - $query->execute([(int) $approved, $magnetCommentId]); - - return $query->rowCount(); - } - - public function getMagnetCommentsTotal() : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->query('SELECT COUNT(*) AS `result` FROM `magnetComment`'); - - return $query->fetch()->result; - } - - public function getMagnetComments() { - - $this->_debug->query->select->total++; - - $query = $this->_db->query('SELECT * FROM `magnetComment`'); - - return $query->fetchAll(); - } - - public function findMagnetCommentsTotalByMagnetId(int $magnetId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(DISTINCT `userId`) AS `result` FROM `magnetComment` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return $query->fetch()->result; - } - - public function findMagnetCommentsTotalByUserId(int $userId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(DISTINCT `magnetId`) AS `result` FROM `magnetComment` WHERE `userId` = ?'); - - $query->execute([$userId]); - - return $query->fetch()->result; - } - - public function findMagnetCommentsTotal(int $magnetId, int $userId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `magnetComment` WHERE `magnetId` = ? AND `userId` = ?'); - - $query->execute([$magnetId, $userId]); - - return $query->fetch()->result; - } - - public function findMagnetCommentsTotalByUsersPublic(bool $public) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `magnetComment` - JOIN `user` ON (`user`.`userId` = `magnetComment`.`userId`) - WHERE `user`.`public` = ?'); - - $query->execute([(int) $public]); - - return $query->fetch()->result; - } - - public function findMagnetComments(int $magnetId, mixed $magnetCommentIdParent = null) { - - $this->_debug->query->select->total++; - - if ($magnetCommentIdParent) - { - $query = $this->_db->prepare('SELECT * FROM `magnetComment` WHERE `magnetId` = ? AND `magnetCommentIdParent` = ?'); - - $query->execute([$magnetId, $magnetCommentIdParent]); - } - else - { - $query = $this->_db->prepare('SELECT * FROM `magnetComment` WHERE `magnetId` = ? AND `magnetCommentIdParent` IS NULL'); - - $query->execute([$magnetId]); - } - - return $query->fetchAll(); - } - - public function findMagnetComment(int $magnetId, int $userId, int $timeAdded) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetComment` WHERE `magnetId` = ? AND `userId` = ? AND `timeAdded` = ?'); - - $query->execute([$magnetId, $userId, $timeAdded]); - - return $query->fetch(); - } - - public function getMagnetComment(int $magnetCommentId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetComment` WHERE `magnetCommentId` = ?'); - - $query->execute([$magnetCommentId]); - - return $query->fetch(); - } - - // Magnet star - public function addMagnetStar(int $magnetId, int $userId, bool $value, int $timeAdded) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `magnetStar` SET `magnetId` = ?, `userId` = ?, `value` = ?, `timeAdded` = ?'); - - $query->execute([$magnetId, $userId, (int) $value, $timeAdded]); - - return $this->_db->lastInsertId(); - } - - public function getMagnetStar(int $magnetStarId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetStar` WHERE `magnetStarId` = ?'); - - $query->execute([$magnetStarId]); - - return $query->fetch(); - } - - public function getMagnetStars() { - - $this->_debug->query->select->total++; - - $query = $this->_db->query('SELECT * FROM `magnetStar`'); - - return $query->fetchAll(); - } - - public function getMagnetStarsTotal() : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->query('SELECT COUNT(*) AS `result` FROM `magnetStar`'); - - return $query->fetch()->result; - } - - public function findMagnetStarsTotalByMagnetId(int $magnetId, bool $value) : int { - - $this->_debug->query->select->total++; - - $total = 0; - - $query = $this->_db->prepare('SELECT COUNT(DISTINCT `userId`) AS `result` FROM `magnetStar` WHERE `magnetId` = ? AND `value` = ?'); - - $query->execute([$magnetId, (int) $value]); - - return $query->fetch()->result; - } - - public function findMagnetStarsTotalByUserId(int $userId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(DISTINCT `magnetId`) AS `result` FROM `magnetStar` WHERE `userId` = ?'); - - $query->execute([$userId]); - - return $query->fetch()->result; - } - - public function findLastMagnetStarValue(int $magnetId, int $userId) : bool { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetStar` WHERE `magnetId` = ? AND `userId` = ? ORDER BY `magnetStarId` DESC'); - - $query->execute([$magnetId, $userId]); - - return $query->rowCount() ? (bool) $query->fetch()->value : false; - } - - public function findMagnetStarsTotalByUsersPublic(bool $public) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `magnetStar` - JOIN `user` ON (`user`.`userId` = `magnetStar`.`userId`) - WHERE `user`.`public` = ?'); - - $query->execute([(int) $public]); - - return $query->fetch()->result; - } - - public function findMagnetStar(int $magnetId, int $userId, int $timeAdded) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetStar` WHERE `magnetId` = ? AND `userId` = ? AND `timeAdded` = ?'); - - $query->execute([$magnetId, $userId, $timeAdded]); - - return $query->fetch(); - } - - // Magnet download - public function addMagnetDownload(int $magnetId, int $userId, int $timeAdded) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `magnetDownload` SET `magnetId` = ?, `userId` = ?, `timeAdded` = ?'); - - $query->execute([$magnetId, $userId, $timeAdded]); - - return $this->_db->lastInsertId(); - } - - public function getMagnetDownload(int $magnetDownloadId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetDownload` WHERE `magnetDownloadId` = ?'); - - $query->execute([$magnetDownloadId]); - - return $query->fetch(); - } - - public function getMagnetDownloads() { - - $this->_debug->query->select->total++; - - $query = $this->_db->query('SELECT * FROM `magnetDownload`'); - - return $query->fetchAll(); - } - - public function getMagnetDownloadsTotal() : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->query('SELECT COUNT(*) AS `result` FROM `magnetDownload`'); - - return $query->fetch()->result; - } - - public function findMagnetDownloadsTotal(int $magnetId, int $userId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `magnetDownload` WHERE `magnetId` = ? AND `userId` = ?'); - - $query->execute([$magnetId, $userId]); - - return $query->fetch()->result; - } - - public function findMagnetDownload(int $magnetId, int $userId, int $timeAdded) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetDownload` WHERE `magnetId` = ? AND `userId` = ? AND `timeAdded` = ?'); - - $query->execute([$magnetId, $userId, $timeAdded]); - - return $query->fetch(); - } - - public function findMagnetDownloadsTotalByMagnetId(int $magnetId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(DISTINCT `userId`) AS `result` FROM `magnetDownload` WHERE `magnetId` = ?'); - - $query->execute([$magnetId]); - - return $query->fetch()->result; - } - - public function findMagnetDownloadsTotalByUserId(int $userId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(DISTINCT `magnetId`) AS `result` FROM `magnetDownload` WHERE `userId` = ?'); - - $query->execute([$userId]); - - return $query->fetch()->result; - } - - public function findMagnetDownloadsTotalByUsersPublic(bool $public) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `magnetDownload` - JOIN `user` ON (`user`.`userId` = `magnetDownload`.`userId`) - WHERE `user`.`public` = ?'); - - $query->execute([(int) $public]); - - return $query->fetch()->result; - } - - // Magnet view - public function addMagnetView(int $magnetId, int $userId, int $timeAdded) : int { - - $this->_debug->query->insert->total++; - - $query = $this->_db->prepare('INSERT INTO `magnetView` SET `magnetId` = ?, `userId` = ?, `timeAdded` = ?'); - - $query->execute([$magnetId, $userId, $timeAdded]); - - return $this->_db->lastInsertId(); - } - - public function getMagnetViews() { - - $this->_debug->query->select->total++; - - $query = $this->_db->query('SELECT * FROM `magnetView`'); - - return $query->fetchAll(); - } - - public function getMagnetView(int $magnetViewId) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetView` WHERE `magnetViewId` = ?'); - - $query->execute([$magnetViewId]); - - return $query->fetch(); - } - - public function getMagnetViewsTotal() : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->query('SELECT COUNT(*) AS `result` FROM `magnetView`'); - - return $query->fetch()->result; - } - - public function findMagnetViewsTotalByUserId(int $userId) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `magnetView` WHERE `userId` = ?'); - - $query->execute([$userId]); - - return $query->fetch()->result; - } - - public function findMagnetViewsTotalByUsersPublic(bool $public) : int { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT COUNT(*) AS `result` FROM `magnetView` - JOIN `user` ON (`user`.`userId` = `magnetView`.`userId`) - WHERE `user`.`public` = ?'); - - $query->execute([(int) $public]); - - return $query->fetch()->result; - } - - public function findMagnetView(int $magnetId, int $userId, int $timeAdded) { - - $this->_debug->query->select->total++; - - $query = $this->_db->prepare('SELECT * FROM `magnetView` WHERE `magnetId` = ? AND `userId` = ? AND `timeAdded` = ?'); - - $query->execute([$magnetId, $userId, $timeAdded]); - - return $query->fetch(); - } -} \ No newline at end of file diff --git a/src/app/model/locale.php b/src/app/model/locale.php deleted file mode 100644 index 91272b1..0000000 --- a/src/app/model/locale.php +++ /dev/null @@ -1,37 +0,0 @@ - $value) - { - $this->_locales[] = (object) - [ - 'code' => $code, - 'value' => $value[0], - 'active' => false, - ]; - } - } - - public function getList() : object - { - return (object) $this->_locales; - } - - public function codeExists(string $code) : bool - { - foreach ($this->_locales as $locale) - { - if ($locale->code === $code) - { - return true; - } - } - - return false; - } -} diff --git a/src/app/model/request.php b/src/app/model/request.php deleted file mode 100644 index e6697fa..0000000 --- a/src/app/model/request.php +++ /dev/null @@ -1,104 +0,0 @@ -_get = $get; - $this->_post = $post; - $this->_files = $files; - $this->_server = $server; - } - - public function get(string $key, mixed $value = null) : mixed - { - if ($value) - { - $this->_get[$key] = $value; - } - - if (isset($this->_get[$key])) - { - return $this->_get[$key]; - } - - else - { - return false; - } - } - - public function post(string $key, mixed $value = null) : mixed - { - if ($value) - { - $this->_get[$key] = $value; - } - - if (isset($this->_post[$key])) - { - return $this->_post[$key]; - } - - else - { - return false; - } - } - - public function files(string $key, mixed $value = null) : mixed - { - if ($value) - { - $this->_get[$key] = $value; - } - - if (isset($this->_files[$key])) - { - return $this->_files[$key]; - } - - else - { - return false; - } - } - - public function server(string $key, mixed $value = null) : mixed - { - if ($value) - { - $this->_get[$key] = $value; - } - - if (isset($this->_get[$key])) - { - return $this->_get[$key]; - } - - else - { - return false; - } - } - - public function hasPost() : bool - { - return !empty($this->_post); - } - - public function hasGet() : bool - { - return !empty($this->_get); - } - - public function hasFiles() : bool - { - return !empty($this->_files); - } -} diff --git a/src/app/model/sphinx.php b/src/app/model/sphinx.php deleted file mode 100644 index db2f8be..0000000 --- a/src/app/model/sphinx.php +++ /dev/null @@ -1,111 +0,0 @@ -_sphinx = new PDO('mysql:host=' . $host . ';port=' . $port . ';charset=utf8', false, false, [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8']); - $this->_sphinx->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - $this->_sphinx->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ); - } - - public function searchMagnetsTotal(string $keyword, string $mode = 'default', array $stopWords = []) : int - { - $query = $this->_sphinx->prepare('SELECT COUNT(*) AS `total` FROM `magnet` WHERE MATCH(?)'); - - $query->execute( - [ - self::_match($keyword, $mode, $stopWords) - ] - ); - - return $query->fetch()->total; - } - - public function searchMagnets(string $keyword, int $start, int $limit, int $maxMatches, string $mode = 'default', array $stopWords = []) - { - $query = $this->_sphinx->prepare("SELECT * - - FROM `magnet` - - WHERE MATCH(?) - - ORDER BY `magnetId` DESC, WEIGHT() DESC - - LIMIT " . (int) ($start >= $maxMatches ? ($maxMatches > 0 ? $maxMatches - 1 : 0) : $start) . "," . (int) $limit . " - - OPTION `max_matches`=" . (int) ($maxMatches >= 1 ? $maxMatches : 1)); - - $query->execute( - [ - self::_match($keyword, $mode, $stopWords) - ] - ); - - return $query->fetchAll(); - } - - private static function _match(string $keyword, string $mode = 'default', array $stopWords = []) : string - { - $keyword = trim($keyword); - - if (empty($keyword)) - { - return $keyword; - } - - $keyword = str_replace(['"'], ' ', $keyword); - $keyword = preg_replace('/[\W]/ui', ' ', $keyword); - $keyword = preg_replace('/[\s]+/ui', ' ', $keyword); - $keyword = trim($keyword); - - switch ($mode) - { - case 'similar': - - $result = []; - - $keyword = preg_replace('/[\d]/ui', ' ', $keyword); - $keyword = preg_replace('/[\s]+/ui', ' ', $keyword); - $keyword = trim($keyword); - - foreach ((array) explode(' ', $keyword) as $value) - { - if (mb_strlen($value) > 5) - { - if (!in_array(mb_strtolower($value), array_map('strtolower', $stopWords))) - { - $result[] = sprintf('@title "%s" | @dn "%s"', $value, $value); - } - } - } - - if (empty($result)) - { - return '*'; - } - else - { - return implode(' | ', $result); - } - - break; - - default: - - $result = []; - - foreach ((array) explode(' ', $keyword) as $value) - { - if (!in_array(mb_strtolower($value), $stopWords)) - { - $result[] = sprintf('@"*%s*"', $value); - } - } - - return implode(' | ', $result); - } - } -} diff --git a/src/app/model/validator.php b/src/app/model/validator.php deleted file mode 100644 index 9040953..0000000 --- a/src/app/model/validator.php +++ /dev/null @@ -1,2216 +0,0 @@ -_config = $config; - } - - // Page - - /// Page title - public function getPageTitleRequired() : bool - { - return $this->_config->page->title->required; - } - - public function getPageTitleLengthMin() : int - { - return $this->_config->page->title->length->min; - } - - public function getPageTitleLengthMax() : int - { - return $this->_config->page->title->length->max; - } - - public function getPageTitleRegex() : string - { - return $this->_config->page->title->regex; - } - - public function pageTitle(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid page title data type') - ); - - return false; - } - - if (empty($value) && $this->getPageTitleRequired()) - { - array_push( - $error, - _('Page title required') - ); - - return false; - } - - if (!preg_match($this->getPageTitleRegex(), $value)) - { - array_push( - $error, - sprintf( - _('Page title format does not match condition "%s"'), - $this->getPageTitleRegex() - ) - ); - - return false; - } - - if (mb_strlen($value) < $this->getPageTitleLengthMin() || - mb_strlen($value) > $this->getPageTitleLengthMax()) - { - array_push( - $error, - sprintf( - _('Page title out of %s-%s chars range'), - $this->getPageTitleLengthMin(), - $this->getPageTitleLengthMax() - ) - ); - - return false; - } - - return true; - } - - /// Page description - public function getPageDescriptionRequired() : bool - { - return $this->_config->page->description->required; - } - - public function getPageDescriptionLengthMin() : int - { - return $this->_config->page->description->length->min; - } - - public function getPageDescriptionLengthMax() : int - { - return $this->_config->page->description->length->max; - } - - public function getPageDescriptionRegex() : string - { - return $this->_config->page->description->regex; - } - - public function pageDescription(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid page description data type') - ); - - return false; - } - - if (empty($value) && $this->getPageDescriptionRequired()) - { - array_push( - $error, - _('Page description required') - ); - - return false; - } - - if (!preg_match($this->getPageDescriptionRegex(), $value)) - { - array_push( - $error, - sprintf( - _('Page description format does not match condition "%s"'), - $this->getPageDescriptionRegex() - ) - ); - - return false; - } - - if (mb_strlen($value) < $this->getPageDescriptionLengthMin() || - mb_strlen($value) > $this->getPageDescriptionLengthMax()) - { - array_push( - $error, - sprintf( - _('Page description out of %s-%s chars range'), - $this->getPageDescriptionLengthMin(), - $this->getPageDescriptionLengthMax() - ) - ); - - return false; - } - - return true; - } - - /// Page keywords - public function getPageKeywordsRequired() : bool - { - return $this->_config->page->keywords->required; - } - - public function getPageKeywordsQuantityMin() : int - { - return $this->_config->page->keywords->quantity->min; - } - - public function getPageKeywordsQuantityMax() : int - { - return $this->_config->page->keywords->quantity->max; - } - - public function pageKeywords(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid page keywords data type') - ); - - return false; - } - - if (empty($value) && $this->getPageKeywordsRequired()) - { - array_push( - $error, - _('Page keywords required') - ); - - return false; - } - - if ($this->getPageKeywordsRequired()) - { - $total = 0; - - foreach (explode(PHP_EOL, str_replace(['#', ',', ' '], PHP_EOL, $value)) as $keyword) - { - $error = []; - - if (!$this->pageKeyword($keyword, $error)) - { - array_push( - $error, - _('Invalid page keyword'), - ); - - return false; - } - - $total++; - } - - if ($total < $this->getPageKeywordsQuantityMin() || - $total > $this->getPageKeywordsQuantityMax()) - { - array_push( - $error, - sprintf( - _('Page keywords quantity out of %s-%s range'), - $this->getPageKeywordsQuantityMin(), - $this->getPageKeywordsQuantityMax() - ) - ); - - return false; - } - } - - return true; - } - - /// Page keyword - public function getPageKeywordLengthMin() : int - { - return $this->_config->page->keyword->length->min; - } - - public function getPageKeywordLengthMax() : int - { - return $this->_config->page->keyword->length->max; - } - - public function getPageKeywordRegex() : string - { - return $this->_config->page->keyword->regex; - } - - public function pageKeyword(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid page keyword data type') - ); - - return false; - } - - if (!preg_match($this->getPageKeywordRegex(), $value)) - { - array_push( - $error, - sprintf( - _('Page keyword format does not match condition "%s"'), - $this->getPageKeywordRegex() - ) - ); - - return false; - } - - if (mb_strlen($value) < $this->getPageKeywordLengthMin() || - mb_strlen($value) > $this->getPageKeywordLengthMax()) - { - array_push( - $error, - sprintf( - _('Page keyword out of %s-%s chars range'), - $this->getPageKeywordLengthMin(), - $this->getPageKeywordLengthMax() - ) - ); - - return false; - } - - return true; - } - - /// Page image - public function getPageImageRequired() : bool - { - return $this->_config->page->image->required; - } - - public function getPageImageMimeTypes() : array - { - return $this->_config->page->image->mime; - } - - /// Page torrent - public function getPageTorrentRequired() : bool - { - return $this->_config->page->torrent->required; - } - - public function getPageTorrentMimeTypes() : array - { - return $this->_config->page->torrent->mime; - } - - // Common - public function host(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid host data type') - ); - - return false; - } - - if (!filter_var(str_replace(['[',']'], false, $value), FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) - { - array_push( - $error, - sprintf( - _('Host "%s" not supported'), - $value - ) - ); - - return false; - } - - if (!preg_match($this->_config->host->regex, str_replace(['[',']'], false, $value))) - { - array_push( - $error, - sprintf( - _('Host "%s" not match condition "%s"'), - $value, - $this->_config->host->regex - ) - ); - - return false; - } - - return true; - } - - public function url(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid URL data type') - ); - - return false; - } - - if (!filter_var($value, FILTER_VALIDATE_URL)) - { - array_push( - $error, - sprintf( - _('URL "%s" invalid'), - $value - ) - ); - - return false; - } - - if (!$host = parse_url($value, PHP_URL_HOST)) - { - array_push( - $error, - sprintf( - _('Could not init host for URL "%s"'), - $value - ) - ); - - return false; - } - - if (!self::host($host, $error)) - { - array_push( - $error, - sprintf( - _('URL "%s" has not supported host "%s"'), - $value, - $host, - ) - ); - - return false; - } - - return true; - } - - // User - public function user(mixed $value, array &$error = []) : bool - { - if (!is_object($value)) - { - array_push( - $error, - _('Invalid user data type') - ); - - return false; - } - - // Validate required fields - if (!isset($value->userId) || !self::userId($value->userId, $error) || - !isset($value->address) || !self::userAddress($value->address, $error) || - !isset($value->timeAdded) || !self::userTimeAdded($value->timeAdded, $error) || - !isset($value->timeUpdated) || !self::userTimeUpdated($value->timeUpdated, $error) || - !isset($value->approved) || !self::userApproved($value->approved, $error) || - - (isset($value->public) && !self::userPublic($value->public, $error))) - { - array_push( - $error, - _('Invalid user data protocol') - ); - - return false; - } - - return true; - } - - public function userId(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid userId data type') - ); - - return false; - } - - return true; - } - - public function userAddress(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid user address data type') - ); - - return false; - } - - if (!self::host($value, $error)) - { - array_push( - $error, - sprintf( - _('User address "%s" not supported'), - $value - ) - ); - - return false; - } - - return true; - } - - public function userTimeAdded(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid user timeAdded data type') - ); - - return false; - } - - if ($value > time() || $value < 0) - { - array_push( - $error, - _('User timeAdded out of range') - ); - - return false; - } - - return true; - } - - public function userTimeUpdated(mixed $value, array &$error = []) : bool - { - if (!(is_int($value) || is_bool($value))) - { - array_push( - $error, - _('Invalid user timeUpdated data type') - ); - - return false; - } - - if (is_int($value) && ($value > time() || $value < 0)) - { - array_push( - $error, - _('User timeUpdated out of range') - ); - - return false; - } - - return true; - } - - public function userApproved(mixed $value, array &$error = []) : bool - { - if (!is_bool($value)) - { - array_push( - $error, - _('Invalid user approved data type') - ); - - return false; - } - - return true; - } - - public function userPublic(mixed $value, array &$error = []) : bool - { - if (!is_bool($value)) - { - array_push( - $error, - _('Invalid user public data type') - ); - - return false; - } - - return true; - } - - // Magnet - public function magnet(mixed $value, array &$error = []) : bool - { - if (!is_object($value)) - { - array_push( - $error, - _('Invalid magnet data type') - ); - - return false; - } - - // Validate required fields by protocol - if (!isset($value->userId) || !self::userId($value->userId, $error) || - - !isset($value->magnetId) || !self::magnetId($value->magnetId, $error) || - - - !isset($value->title) || !self::magnetTitle($value->title, $error) || - !isset($value->preview) || !self::magnetPreview($value->preview, $error) || - !isset($value->description) || !self::magnetDescription($value->description, $error) || - - !isset($value->comments) || !self::magnetComments($value->comments, $error) || - !isset($value->sensitive) || !self::magnetSensitive($value->sensitive, $error) || - !isset($value->approved) || !self::magnetApproved($value->approved, $error) || - - !isset($value->timeAdded) || !self::magnetTimeAdded($value->timeAdded, $error) || - !isset($value->timeUpdated) || !self::magnetTimeUpdated($value->timeUpdated, $error) || - - !isset($value->dn) || !self::magnetDn($value->dn, $error) || - !isset($value->xt) || !self::magnetXt($value->xt, $error) || - - !isset($value->xl) || !self::magnetXl($value->xl, $error) || - - !isset($value->kt) || !self::magnetKt($value->kt, $error) || - !isset($value->tr) || !self::magnetTr($value->tr, $error) || - !isset($value->as) || !self::magnetAs($value->as, $error) || - !isset($value->xs) || !self::magnetWs($value->xs, $error) || - - (isset($value->public) && !self::magnetPublic($value->public, $error))) - { - array_push( - $error, - _('Invalid magnet data protocol') - ); - - return false; - } - - return true; - } - - public function magnetId(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid magnetId data type') - ); - - return false; - } - - return true; - } - - public function magnetTitle(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid magnet title data type') - ); - - return false; - } - - if (!preg_match(MAGNET_TITLE_REGEX, $value)) - { - array_push( - $error, - sprintf( - _('Magnet title format does not match condition "%s"'), - MAGNET_TITLE_REGEX - ) - ); - - return false; - } - - if (mb_strlen($value) < MAGNET_TITLE_MIN_LENGTH || - mb_strlen($value) > MAGNET_TITLE_MAX_LENGTH) - { - array_push( - $error, - sprintf( - _('Magnet title out of %s-%s chars range'), - MAGNET_TITLE_MIN_LENGTH, - MAGNET_TITLE_MAX_LENGTH - ) - ); - - return false; - } - - return true; - } - - public function magnetPreview(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid magnet preview data type') - ); - - return false; - } - - if (!preg_match(MAGNET_PREVIEW_REGEX, $value)) - { - array_push( - $error, - sprintf( - _('Magnet preview format does not match condition "%s"'), - MAGNET_PREVIEW_REGEX - ) - ); - - return false; - } - - if (mb_strlen($value) < MAGNET_PREVIEW_MIN_LENGTH || - mb_strlen($value) > MAGNET_PREVIEW_MAX_LENGTH) - { - array_push( - $error, - sprintf( - _('Magnet preview out of %s-%s chars range'), - MAGNET_PREVIEW_MIN_LENGTH, - MAGNET_PREVIEW_MAX_LENGTH - ) - ); - - return false; - } - - return true; - } - - public function magnetDescription(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid magnet description data type') - ); - - return false; - } - - if (!preg_match(MAGNET_DESCRIPTION_REGEX, $value)) - { - array_push( - $error, - sprintf( - _('Magnet description format does not match condition "%s"'), - MAGNET_DESCRIPTION_REGEX - ) - ); - - return false; - } - - if (mb_strlen($value) < MAGNET_DESCRIPTION_MIN_LENGTH || - mb_strlen($value) > MAGNET_DESCRIPTION_MAX_LENGTH) - { - array_push( - $error, - sprintf( - _('Magnet description out of %s-%s chars range'), - MAGNET_DESCRIPTION_MIN_LENGTH, - MAGNET_DESCRIPTION_MAX_LENGTH - ) - ); - - return false; - } - - return true; - } - - public function magnetComments(mixed $value, array &$error = []) : bool - { - if (!is_bool($value)) - { - array_push( - $error, - _('Invalid magnet comments data type') - ); - - return false; - } - - return true; - } - - public function magnetPublic(mixed $value, array &$error = []) : bool - { - if (!is_bool($value)) - { - array_push( - $error, - _('Invalid magnet public data type') - ); - - return false; - } - - return true; - } - - public function magnetApproved(mixed $value, array &$error = []) : bool - { - if (!is_bool($value)) - { - array_push( - $error, - _('Invalid magnet approved data type') - ); - - return false; - } - - return true; - } - - public function magnetSensitive(mixed $value, array &$error = []) : bool - { - if (!is_bool($value)) - { - array_push( - $error, - _('Invalid magnet sensitive data type') - ); - - return false; - } - - return true; - } - - public function magnetTimeAdded(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid magnet timeAdded data type') - ); - - return false; - } - - if ($value > time() || $value < 0) - { - array_push( - $error, - _('Magnet timeAdded out of range') - ); - - return false; - } - - return true; - } - - public function magnetTimeUpdated(mixed $value, array &$error = []) : bool - { - if (!(is_int($value) || is_bool($value))) - { - array_push( - $error, - _('Invalid magnet timeUpdated data type') - ); - - return false; - } - - if (is_int($value) && ($value > time() || $value < 0)) - { - array_push( - $error, - _('Magnet timeUpdated out of range') - ); - - return false; - } - - return true; - } - - public function magnetDn(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid magnet display name data type') - ); - - return false; - } - - if (!preg_match(MAGNET_DN_REGEX, $value)) - { - array_push( - $error, - sprintf( - _('Magnet display name format does not match condition "%s"'), - MAGNET_DN_REGEX - ) - ); - - return false; - } - - if (mb_strlen($value) < MAGNET_DN_MIN_LENGTH || - mb_strlen($value) > MAGNET_DN_MAX_LENGTH) - { - array_push( - $error, - sprintf( - _('Magnet display name out of %s-%s chars range'), - MAGNET_DN_MIN_LENGTH, - MAGNET_DN_MAX_LENGTH - ) - ); - - return false; - } - - return true; - } - - public function magnetXl(mixed $value, array &$error = []) : bool - { - if (!(is_int($value) || is_float($value))) - { - array_push( - $error, - _('Invalid magnet exact length data type') - ); - - return false; - } - - return true; - } - - public function magnetKt(mixed $value, array &$error = []) : bool - { - if (!is_object($value)) - { - array_push( - $error, - _('Invalid magnet keyword data type') - ); - - return false; - } - - $total = 0; - - foreach ($value as $kt) - { - if (!is_string($kt)) - { - array_push( - $error, - _('Invalid magnet keyword value data type') - ); - - return false; - } - - if (!preg_match(MAGNET_KT_REGEX, $kt)) - { - array_push( - $error, - sprintf( - _('Magnet keyword format does not match condition "%s"'), - MAGNET_KT_REGEX - ) - ); - - return false; - } - - if (mb_strlen($kt) < MAGNET_KT_MIN_LENGTH || - mb_strlen($kt) > MAGNET_KT_MAX_LENGTH) - { - array_push( - $error, - sprintf( - _('Magnet keyword out of %s-%s chars range'), - MAGNET_KT_MIN_LENGTH, - MAGNET_KT_MAX_LENGTH - ) - ); - - return false; - } - - $total++; - } - - if ($total < MAGNET_KT_MIN_QUANTITY || - $total > MAGNET_KT_MAX_QUANTITY) - { - array_push( - $error, - sprintf( - _('Magnet keywords quantity out of %s-%s range'), - MAGNET_KT_MIN_QUANTITY, - MAGNET_KT_MAX_QUANTITY - ) - ); - - return false; - } - - return true; - } - - public function magnetXt(mixed $value, array &$error = []) : bool - { - if (!is_object($value)) - { - array_push( - $error, - _('Invalid magnet info hash data type') - ); - - return false; - } - - foreach ($value as $xt) - { - if (empty($xt->version)) - { - array_push( - $error, - _('Magnet info hash version required') - ); - - return false; - } - - if (!(is_int($xt->version) || is_float($xt->version))) - { - array_push( - $error, - _('Invalid magnet info hash version data type') - ); - - return false; - } - - if (empty($xt->value)) - { - array_push( - $error, - _('Magnet info hash value required') - ); - - return false; - } - - if (!is_string($xt->value)) - { - array_push( - $error, - _('Invalid magnet info hash value data type') - ); - - return false; - } - - switch ($xt->version) - { - case 1: - - if (!preg_match('/^([A-z0-9]{40})$/i', $xt->value)) - { - array_push( - $error, - _('Invalid magnet info hash v1 value') - ); - - return false; - } - - break; - - case 2: - - if (!preg_match('/^([A-z0-9]{64})$/i', $xt->value)) - { - array_push( - $error, - _('Invalid magnet info hash v2 value') - ); - - return false; - } - - break; - - default: - - array_push( - $error, - _('Magnet info hash version not supported') - ); - - return false; - } - } - - return true; - } - - public function magnetTr(mixed $value, array &$error = []) : bool - { - if (!is_object($value)) - { - array_push( - $error, - _('Invalid magnet address tracker data type') - ); - - return false; - } - - $total = 0; - - foreach ($value as $tr) - { - if (!self::url($tr, $error)) - { - array_push( - $error, - sprintf( - _('Invalid magnet address tracker URL "%s"'), - $tr - ) - ); - - return false; - } - - $total++; - } - - if ($total < MAGNET_TR_MIN_QUANTITY || - $total > MAGNET_TR_MAX_QUANTITY) - { - array_push( - $error, - sprintf( - _('Magnet address trackers quantity out of %s-%s range'), - MAGNET_TR_MIN_QUANTITY, - MAGNET_TR_MAX_QUANTITY - ) - ); - - return false; - } - - return true; - } - - public function magnetAs(mixed $value, array &$error = []) : bool - { - if (!is_object($value)) - { - array_push( - $error, - _('Invalid magnet acceptable source data type') - ); - - return false; - } - - $total = 0; - - foreach ($value as $as) - { - if (!self::url($as, $error)) - { - array_push( - $error, - sprintf( - _('Invalid magnet acceptable source URL "%s"'), - $as - ) - ); - - return false; - } - - $total++; - } - - if ($total < MAGNET_AS_MIN_QUANTITY || - $total > MAGNET_AS_MAX_QUANTITY) - { - array_push( - $error, - sprintf( - _('Magnet acceptable sources quantity out of %s-%s range'), - MAGNET_AS_MIN_QUANTITY, - MAGNET_AS_MAX_QUANTITY - ) - ); - - return false; - } - - return true; - } - - public function magnetWs(mixed $value, array &$error = []) : bool - { - if (!is_object($value)) - { - array_push( - $error, - _('Invalid magnet web seed data type') - ); - - return false; - } - - $total = 0; - - foreach ($value as $ws) - { - if (!self::url($ws, $error)) - { - array_push( - $error, - sprintf( - _('Invalid magnet web seed URL "%s"'), - $ws - ) - ); - - return false; - } - - $total++; - } - - if ($total < MAGNET_WS_MIN_QUANTITY || - $total > MAGNET_WS_MAX_QUANTITY) - { - array_push( - $error, - sprintf( - _('Magnet web seeds quantity out of %s-%s range'), - MAGNET_WS_MIN_QUANTITY, - MAGNET_WS_MAX_QUANTITY - ) - ); - - return false; - } - - return true; - } - - // Magnet comment - public function magnetComment(mixed $value, array &$error = []) : bool - { - if (!is_object($value)) - { - array_push( - $error, - _('Invalid magnet comment data type') - ); - - return false; - } - - if (!isset($value->magnetCommentId) || !self::magnetCommentId($value->magnetCommentId, $error) || - !isset($value->magnetId) || !self::magnetId($value->magnetId, $error) || - !isset($value->userId) || !self::userId($value->userId, $error) || - !isset($value->timeAdded) || !self::magnetCommentTimeAdded($value->timeAdded, $error) || - !isset($value->approved) || !self::magnetCommentApproved($value->approved, $error) || - !isset($value->value) || !self::magnetCommentValue($value->value, $error) || - - (isset($value->magnetCommentIdParent) && !self::magnetCommentIdParent($value->magnetCommentIdParent, $error)) || - - (isset($value->public) && !self::magnetCommentPublic($value->public, $error))) - { - array_push( - $error, - _('Invalid magnet comment data protocol') - ); - - return false; - } - - return true; - } - - public function magnetCommentId(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid magnetCommentId data type') - ); - - return false; - } - - return true; - } - - public function magnetCommentIdParent(mixed $value, array &$error = []) : bool - { - if (!(is_null($value) || is_int($value))) - { - array_push( - $error, - _('Invalid magnet magnetCommentIdParent data type') - ); - - return false; - } - - if (is_int($value) && !self::magnetCommentId($value, $error)) - { - return false; - } - - return true; - } - - public function magnetCommentTimeAdded(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid magnet comment timeAdded data type') - ); - - return false; - } - - if ($value > time() || $value < 0) - { - array_push( - $error, - _('Magnet comment timeAdded out of range') - ); - - return false; - } - - return true; - } - - public function magnetCommentApproved(mixed $value, array &$error = []) : bool - { - if (!is_bool($value)) - { - array_push( - $error, - _('Invalid magnet comment approved data type') - ); - - return false; - } - - return true; - } - - public function magnetCommentPublic(mixed $value, array &$error = []) : bool - { - if (!is_bool($value)) - { - array_push( - $error, - _('Invalid magnet comment public data type') - ); - - return false; - } - - return true; - } - - public function magnetCommentValue(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid magnet comment value data type') - ); - - return false; - } - - if (mb_strlen($value) < MAGNET_COMMENT_MIN_LENGTH || - mb_strlen($value) > MAGNET_COMMENT_MAX_LENGTH) - { - array_push( - $error, - sprintf( - _('Magnet comment value out of %s-%s chars range'), - MAGNET_COMMENT_MIN_LENGTH, - MAGNET_COMMENT_MAX_LENGTH - ) - ); - - return false; - } - - return true; - } - - // Magnet download - public function magnetDownload(mixed $value, array &$error = []) : bool - { - if (!is_object($value)) - { - array_push( - $error, - _('Invalid magnet download data type') - ); - - return false; - } - - if (!isset($value->magnetDownloadId) || !self::magnetDownloadId($value->magnetDownloadId, $error) || - !isset($value->magnetId) || !self::magnetId($value->magnetId, $error) || - !isset($value->userId) || !self::userId($value->userId, $error) || - !isset($value->timeAdded) || !self::magnetDownloadTimeAdded($value->timeAdded, $error) - ) - { - array_push( - $error, - _('Invalid magnet download data protocol') - ); - - return false; - } - - return true; - } - - public function magnetDownloadId(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid magnetDownloadId data type') - ); - - return false; - } - - return true; - } - - public function magnetDownloadTimeAdded(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid magnet download timeAdded data type') - ); - - return false; - } - - if ($value > time() || $value < 0) - { - array_push( - $error, - _('Magnet download timeAdded out of range') - ); - - return false; - } - - return true; - } - - // Magnet star - public function magnetStar(mixed $value, array &$error = []) : bool - { - if (!is_object($value)) - { - array_push( - $error, - _('Invalid magnet star data type') - ); - - return false; - } - - if (!isset($value->magnetStarId) || !self::magnetViewId($value->magnetStarId, $error) || - !isset($value->magnetId) || !self::magnetId($value->magnetId, $error) || - !isset($value->userId) || !self::userId($value->userId, $error) || - !isset($value->timeAdded) || !self::magnetStarTimeAdded($value->timeAdded, $error) || - !isset($value->value) || !self::magnetStarValue($value->value, $error) - ) - { - array_push( - $error, - _('Invalid magnet star data protocol') - ); - - return false; - } - - return true; - } - - public function magnetStarId(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid magnetStarId data type') - ); - - return false; - } - - return true; - } - - public function magnetStarValue(mixed $value, array &$error = []) : bool - { - if (!is_bool($value)) - { - array_push( - $error, - _('Invalid magnet star value data type') - ); - - return false; - } - - return true; - } - - public function magnetStarTimeAdded(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid magnet star timeAdded data type') - ); - - return false; - } - - if ($value > time() || $value < 0) - { - array_push( - $error, - _('Magnet star timeAdded out of range') - ); - - return false; - } - - return true; - } - - // Magnet view - public function magnetView(mixed $value, array &$error = []) : bool - { - if (!is_object($value)) - { - array_push( - $error, - _('Invalid magnet view data type') - ); - - return false; - } - - if (!isset($value->magnetViewId) || !self::magnetViewId($value->magnetViewId, $error) || - !isset($value->magnetId) || !self::magnetId($value->magnetId, $error) || - !isset($value->userId) || !self::userId($value->userId, $error) || - !isset($value->timeAdded) || !self::magnetViewTimeAdded($value->timeAdded, $error) - ) - { - array_push( - $error, - _('Invalid magnet view data protocol') - ); - - return false; - } - - return true; - } - - public function magnetViewId(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid magnetViewId data type') - ); - - return false; - } - - return true; - } - - public function magnetViewTimeAdded(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid magnet view timeAdded data type') - ); - - return false; - } - - if ($value > time() || $value < 0) - { - array_push( - $error, - _('Magnet view timeAdded out of range') - ); - - return false; - } - - return true; - } - - // Torrent - public function torrentAnnounce(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid torrent announce data type') - ); - - return false; - } - - if (!self::url($tr, $error)) - { - array_push( - $error, - sprintf( - _('Invalid torrent announce URL "%s"'), - $tr - ) - ); - - return false; - } - - return true; - } - - public function torrentAnnounceList(mixed $value, array &$error = []) : bool - { - if (!is_array($value)) - { - array_push( - $error, - _('Invalid torrent announce data type') - ); - - return false; - } - - $total = 0; - - foreach ($value as $list) - { - if (!is_array($list)) - { - array_push( - $error, - _('Invalid torrent announce list') - ); - - return false; - } - - foreach ($list as $announce) - { - if (!self::torrentAnnounce($announce, $error)) - { - array_push( - $error, - sprintf( - _('Invalid torrent announce list URL "%s"'), - $announce - ) - ); - - return false; - } - - $total++; - } - } - - if ($total < TORRENT_ANNOUNCE_MIN_QUANTITY || - $total > TORRENT_ANNOUNCE_MAX_QUANTITY) - { - array_push( - $error, - sprintf( - _('Torrent announces quantity out of %s-%s range'), - TORRENT_ANNOUNCE_MIN_QUANTITY, - TORRENT_ANNOUNCE_MAX_QUANTITY - ) - ); - - return false; - } - - return true; - } - - public function torrentComment(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid torrent comment data type') - ); - - return false; - } - - if (!preg_match(TORRENT_COMMENT_REGEX, $value)) - { - array_push( - $error, - sprintf( - _('Torrent comment format does not match condition "%s"'), - TORRENT_COMMENT_REGEX - ) - ); - - return false; - } - - if (mb_strlen($value) < TORRENT_COMMENT_MIN_LENGTH || - mb_strlen($value) > TORRENT_COMMENT_MAX_LENGTH) - { - array_push( - $error, - sprintf( - _('Torrent comment out of %s-%s chars range'), - TORRENT_COMMENT_MIN_LENGTH, - TORRENT_COMMENT_MAX_LENGTH - ) - ); - - return false; - } - - return true; - } - - public function torrentCreatedBy(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid torrent created by data type') - ); - - return false; - } - - if (!preg_match(TORRENT_CREATED_BY_REGEX, $value)) - { - array_push( - $error, - sprintf( - _('Torrent created by format does not match condition "%s"'), - TORRENT_CREATED_BY_REGEX - ) - ); - - return false; - } - - if (mb_strlen($value) < TORRENT_CREATED_BY_MIN_LENGTH || - mb_strlen($value) > TORRENT_CREATED_BY_MAX_LENGTH) - { - array_push( - $error, - sprintf( - _('Torrent created by out of %s-%s chars range'), - TORRENT_CREATED_BY_MIN_LENGTH, - TORRENT_CREATED_BY_MAX_LENGTH - ) - ); - - return false; - } - - return true; - } - - public function torrentCreationDate(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid torrent creation date data type') - ); - - return false; - } - - if ($value > time() || $value < 0) - { - array_push( - $error, - _('Torrent creation date out of range') - ); - - return false; - } - - return true; - } - - public function torrentInfo(mixed $value, array &$error = []) : bool - { - if (!is_array($value)) - { - array_push( - $error, - _('Invalid torrent info data type') - ); - - return false; - } - - if (empty($value)) - { - array_push( - $error, - _('Torrent info has no keys') - ); - - return false; - } - - foreach ($value as $info) - { - if (!is_array($info)) - { - array_push( - $error, - _('Invalid torrent info protocol') - ); - - return false; - } - - if (empty($info)) - { - array_push( - $error, - _('Torrent info has no values') - ); - - return false; - } - - foreach ($info as $key => $data) - { - switch ($key) - { - case 'file-duration': - - if (!self::torrentInfoFileDuration($data, $error)) - { - array_push( - $error, - _('Invalid torrent info file-duration') - ); - - return false; - } - - break; - case 'file-media': - - if (!self::torrentInfoFileMedia($data, $error)) - { - array_push( - $error, - _('Invalid torrent info file-media') - ); - - return false; - } - - break; - case 'files': - - if (!self::torrentInfoFiles($data, $error)) - { - array_push( - $error, - _('Invalid torrent info files') - ); - - return false; - } - - break; - case 'name': - - if (!self::torrentInfoName($data, $error)) - { - array_push( - $error, - _('Invalid torrent info name') - ); - - return false; - } - - break; - case 'piece length': - - if (!self::torrentInfoPieceLength($data, $error)) - { - array_push( - $error, - _('Invalid torrent info piece length') - ); - - return false; - } - - break; - case 'pieces': - - if (!self::torrentInfoPieces($data, $error)) - { - array_push( - $error, - _('Invalid torrent info pieces') - ); - - return false; - } - - break; - case 'private': - - if (!self::torrentInfoPrivate($data, $error)) - { - array_push( - $error, - _('Invalid torrent info private') - ); - - return false; - } - - break; - case 'profiles': - - if (!self::torrentInfoProfiles($data, $error)) - { - array_push( - $error, - _('Invalid torrent info profiles') - ); - - return false; - } - - break; - case 'source': - - if (!self::torrentInfoSource($data, $error)) - { - array_push( - $error, - _('Invalid torrent info source') - ); - - return false; - } - - break; - default: - array_push( - $error, - _('Not supported torrent info key') - ); - } - } - } - - return true; - } - - public function torrentInfoName(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid torrent info name data type') - ); - - return false; - } - - if (!preg_match(TORRENT_INFO_NAME_REGEX, $value)) - { - array_push( - $error, - sprintf( - _('Torrent info name format does not match condition "%s"'), - TORRENT_INFO_NAME_REGEX - ) - ); - - return false; - } - - if (mb_strlen($value) < TORRENT_INFO_NAME_MIN_LENGTH || - mb_strlen($value) > TORRENT_INFO_NAME_MAX_LENGTH) - { - array_push( - $error, - sprintf( - _('Torrent info name out of %s-%s chars range'), - TORRENT_INFO_NAME_MIN_LENGTH, - TORRENT_INFO_NAME_MAX_LENGTH - ) - ); - - return false; - } - - return true; - } - - public function torrentInfoSource(mixed $value, array &$error = []) : bool - { - if (!is_string($value)) - { - array_push( - $error, - _('Invalid torrent info source data type') - ); - - return false; - } - - if (!preg_match(TORRENT_INFO_SOURCE_REGEX, $value)) - { - array_push( - $error, - sprintf( - _('Torrent info source format does not match condition "%s"'), - TORRENT_INFO_SOURCE_REGEX - ) - ); - - return false; - } - - if (mb_strlen($value) < TORRENT_INFO_SOURCE_MIN_LENGTH || - mb_strlen($value) > TORRENT_INFO_SOURCE_MAX_LENGTH) - { - array_push( - $error, - sprintf( - _('Torrent info source out of %s-%s chars range'), - TORRENT_INFO_SOURCE_MIN_LENGTH, - TORRENT_INFO_SOURCE_MAX_LENGTH - ) - ); - - return false; - } - - return true; - - return true; - } - - public function torrentInfoFileDuration(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid torrent file-duration data type') - ); - - return false; - } - - if ($value < 0) - { - array_push( - $error, - _('Torrent file-duration out of range') - ); - - return false; - } - - return true; - } - - public function torrentInfoPieceLength(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid torrent info piece length data type') - ); - - return false; - } - - if ($value < 0) - { - array_push( - $error, - _('Torrent torrent info piece length out of range') - ); - - return false; - } - - return true; - } - - public function torrentInfoPieces(mixed $value, array &$error = []) : bool - { - // @TODO - - return true; - } - - public function torrentInfoPrivate(mixed $value, array &$error = []) : bool - { - if (!is_int($value)) - { - array_push( - $error, - _('Invalid torrent info private data type') - ); - - return false; - } - - if (!in_array($value, [0, 1])) - { - array_push( - $error, - _('Invalid torrent info private value') - ); - - return false; - } - - return true; - } - - public function torrentInfoProfiles(mixed $value, array &$error = []) : bool - { - // @TODO - - return true; - } - - public function torrentInfoFileMedia(mixed $value, array &$error = []) : bool - { - // @TODO - - return true; - } - - public function torrentInfoFiles(mixed $value, array &$error = []) : bool - { - // @TODO - - return true; - } -} \ No newline at end of file diff --git a/src/app/model/website.php b/src/app/model/website.php deleted file mode 100644 index f1d4f9f..0000000 --- a/src/app/model/website.php +++ /dev/null @@ -1,46 +0,0 @@ -_config = $config; - } - - public function getConfig() : object - { - return $this->_config->name; - } - - public function getName() : string - { - return $this->_config->name; - } - - public function getUrl() : string - { - return $this->_config->url; - } - - public function getDefaultLocale() : string - { - return $this->_config->default->locale; - } - - public function getDefaultUserStatus() : bool - { - return $this->_config->default->user->status; - } - - public function getDefaultUserApproved() : bool - { - return $this->_config->default->user->approved; - } - - public function getApiExportEnabled() : bool - { - return $this->_config->api->export->enabled; - } -} \ No newline at end of file diff --git a/src/app/view/theme/default/index.phtml b/src/app/view/theme/default/index.phtml deleted file mode 100644 index 4585236..0000000 --- a/src/app/view/theme/default/index.phtml +++ /dev/null @@ -1,32 +0,0 @@ - - - render() ?> - - render() ?> -
-
-
-
- render() ?> - - - render($page->pageId) ?> - - render() ?> - -
-

- -

-
- -
-
- -
-
-
-
- render() ?> - - \ No newline at end of file diff --git a/src/app/view/theme/default/module/footer.phtml b/src/app/view/theme/default/module/footer.phtml deleted file mode 100644 index 0064221..0000000 --- a/src/app/view/theme/default/module/footer.phtml +++ /dev/null @@ -1,27 +0,0 @@ -
-
-
-
- $tracker) { ?> - - / - - | - - - | - - | - - - | - - - | - -
-
-
-
- - \ No newline at end of file diff --git a/src/app/view/theme/default/module/head.phtml b/src/app/view/theme/default/module/head.phtml deleted file mode 100644 index 70c6452..0000000 --- a/src/app/view/theme/default/module/head.phtml +++ /dev/null @@ -1,7 +0,0 @@ - - - <?php echo $title ?> - - - - \ No newline at end of file diff --git a/src/app/view/theme/default/module/header.phtml b/src/app/view/theme/default/module/header.phtml deleted file mode 100644 index 1c622e9..0000000 --- a/src/app/view/theme/default/module/header.phtml +++ /dev/null @@ -1,10 +0,0 @@ -
-
-
- - render() ?> -
-
-
\ No newline at end of file diff --git a/src/app/view/theme/default/module/page.phtml b/src/app/view/theme/default/module/page.phtml deleted file mode 100644 index f242004..0000000 --- a/src/app/view/theme/default/module/page.phtml +++ /dev/null @@ -1,126 +0,0 @@ - -
-
- -

- - - - - -
-
- - - - - - - - - - - - - -
- preview) { ?> -
preview ?>
- - keywords) { ?> -
- keywords as $keyword) { ?> - - # - - -
- -
- - - timeUpdated ? _('Updated') : _('Added') ?> - timeUpdated ? $magnet->timeUpdated : $magnet->timeAdded ?> - - - - - - - seeders ?> - - - - - - completed ?> - - - - - - - leechers ?> - - directs) { ?> - - - - - directs ?> - - - - - star->status) { ?> - - - - - - - - - - star->total ?> - - comments) { ?> - - - comment->status) { ?> - - - - - - - - - - comment->total ?> - - - - - download->status) { ?> - - - - - - - - - - download->total ?> - -
-
\ No newline at end of file diff --git a/src/app/view/theme/default/module/pagination.phtml b/src/app/view/theme/default/module/pagination.phtml deleted file mode 100644 index 1f8422a..0000000 --- a/src/app/view/theme/default/module/pagination.phtml +++ /dev/null @@ -1,15 +0,0 @@ -
-
- page, $pagination->total) ?> - back) { ?> - - - - - next) { ?> - - - - -
-
\ No newline at end of file diff --git a/src/app/view/theme/default/module/search.phtml b/src/app/view/theme/default/module/search.phtml deleted file mode 100644 index 1e62af4..0000000 --- a/src/app/view/theme/default/module/search.phtml +++ /dev/null @@ -1,20 +0,0 @@ -
- - - -
\ No newline at end of file diff --git a/src/app/view/theme/default/page/form/submit.phtml b/src/app/view/theme/default/page/form/submit.phtml deleted file mode 100644 index 629b4f8..0000000 --- a/src/app/view/theme/default/page/form/submit.phtml +++ /dev/null @@ -1,140 +0,0 @@ - - - render() ?> - - render() ?> -
-
-
-
- render() ?> -
-
-

-
-
- -
- - - - - - - -
-
- - - - - - - title->error as $errors) { ?> - -
- -
- - - title->attribute->required ? 'required="required"' : false ?> - value="title->attribute->value ?>" - placeholder="title->attribute->placeholder ?>" - minlength="title->attribute->minlength ?>" - maxlength="title->attribute->maxlength ?>" /> -
-
- - - - - - - description->error as $errors) { ?> - -
- -
- - - -
-
- - - - - - - keywords->error as $errors) { ?> - -
- -
- - - -
-
- sensitive->attribute->value ? 'checked="checked"' : false ?> /> - - - - - - -
-
- -
-
-
-
-
-
-
- render() ?> - - \ No newline at end of file diff --git a/src/app/view/theme/default/response.phtml b/src/app/view/theme/default/response.phtml deleted file mode 100644 index 2438208..0000000 --- a/src/app/view/theme/default/response.phtml +++ /dev/null @@ -1,24 +0,0 @@ - - - render() ?> - - render() ?> -
-
-
-
-
-

- -

-
- -
-
-
-
-
-
- render() ?> - - \ No newline at end of file diff --git a/src/config/bootstrap.php b/src/config/bootstrap.php deleted file mode 100644 index c2e56e6..0000000 --- a/src/config/bootstrap.php +++ /dev/null @@ -1,160 +0,0 @@ -render(); - - break; - - case 'views': - - require_once __DIR__ . '/../app/controller/views.php'; - - $appControllerViews = new AppControllerViews(); - - $appControllerViews->render(); - - break; - - case 'downloads': - - require_once __DIR__ . '/../app/controller/downloads.php'; - - $appControllerDownloads = new AppControllerDownloads(); - - $appControllerDownloads->render(); - - break; - - case 'comments': - - require_once __DIR__ . '/../app/controller/comments.php'; - - $appControllerComments = new AppControllerComments(); - - $appControllerComments->render(); - - break; - - case 'editions': - - require_once __DIR__ . '/../app/controller/editions.php'; - - $appControllerEditions = new AppControllerEditions(); - - $appControllerEditions->render(); - - break; - - case 'submit': - - require_once __DIR__ . '/../app/model/database.php'; - require_once __DIR__ . '/../app/model/validator.php'; - require_once __DIR__ . '/../app/model/locale.php'; - require_once __DIR__ . '/../app/model/website.php'; - require_once __DIR__ . '/../app/model/session.php'; - require_once __DIR__ . '/../app/model/request.php'; - - require_once __DIR__ . '/../app/controller/page.php'; - - $appControllerPage = new AppControllerPage( - new AppModelDatabase( - Environment::config('database') - ), - new AppModelValidator( - Environment::config('validator') - ), - new AppModelLocale( - Environment::config('locales') - ), - new AppModelWebsite( - Environment::config('website') - ), - new AppModelSession( - $_SERVER['REMOTE_ADDR'] - ), - new AppModelRequest( - $_GET, - $_POST, - $_FILES - ) - ); - - $appControllerPage->renderFormSubmit(); - - break; - - default: - - require_once __DIR__ . '/../app/controller/response.php'; - - $appControllerResponse = new AppControllerResponse( - sprintf( - _('404 - Not found - %s'), - Environment::config('website')->name - ), - _('404'), - _('Page not found'), - 404 - ); - - $appControllerResponse->render(); - } -} - -else -{ - require_once __DIR__ . '/../app/model/database.php'; - require_once __DIR__ . '/../app/model/validator.php'; - require_once __DIR__ . '/../app/model/website.php'; - require_once __DIR__ . '/../app/model/session.php'; - - require_once __DIR__ . '/../app/controller/index.php'; - - $appControllerIndex = new AppControllerIndex( - new AppModelDatabase( - Environment::config('database') - ), - new AppModelValidator( - Environment::config('validator') - ), - new AppModelWebsite( - Environment::config('website') - ), - new AppModelSession( - $_SERVER['REMOTE_ADDR'] - ) - ); - - $appControllerIndex->render(); -} diff --git a/src/config/database.json b/src/config/database.json deleted file mode 100644 index 64d4306..0000000 --- a/src/config/database.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "port":3306, - "host":"127.0.0.1", - "name":"", - "user":"", - "password":"" -} \ No newline at end of file diff --git a/src/config/locales.json b/src/config/locales.json deleted file mode 100644 index c124d4b..0000000 --- a/src/config/locales.json +++ /dev/null @@ -1,277 +0,0 @@ -{ - "af-ZA": - [ - "Afrikaans", - "Afrikaans" - ], - "ar": - [ - "العربية", - "Arabic" - ], - "bg-BG": - [ - "Български", - "Bulgarian" - ], - "ca-AD": - [ - "Català", - "Catalan" - ], - "cs-CZ": - [ - "Čeština", - "Czech" - ], - "cy-GB": - [ - "Cymraeg", - "Welsh" - ], - "da-DK": - [ - "Dansk", - "Danish" - ], - "de-AT": - [ - "Deutsch (Österreich)", - "German (Austria)" - ], - "de-CH": - [ - "Deutsch (Schweiz)", - "German (Switzerland)" - ], - "de-DE": - [ - "Deutsch (Deutschland)", - "German (Germany)" - ], - "el-GR": - [ - "Ελληνικά", - "Greek" - ], - "en-GB": - [ - "English (UK)", - "English (UK)" - ], - "en-US": - [ - "English (US)", - "English (US)" - ], - "es-CL": - [ - "Español (Chile)", - "Spanish (Chile)" - ], - "es-ES": - [ - "Español (España)", - "Spanish (Spain)" - ], - "es-MX": - [ - "Español (México)", - "Spanish (Mexico)" - ], - "et-EE": - [ - "Eesti keel", - "Estonian" - ], - "eu": - [ - "Euskara", - "Basque" - ], - "fa-IR": - [ - "فارسی", - "Persian" - ], - "fi-FI": - [ - "Suomi", - "Finnish" - ], - "fr-CA": - [ - "Français (Canada)", - "French (Canada)" - ], - "fr-FR": - [ - "Français (France)", - "French (France)" - ], - "gl-ES": - [ - "Galego (Spain)", - "Galician (Spain)" - ], - "he-IL": - [ - "עברית", - "Hebrew" - ], - "hi-IN": - [ - "हिंदी", - "Hindi" - ], - "hr-HR": - [ - "Hrvatski", - "Croatian" - ], - "hu-HU": - [ - "Magyar", - "Hungarian" - ], - "id-ID": - [ - "Bahasa Indonesia", - "Indonesian" - ], - "is-IS": - [ - "Íslenska", - "Icelandic" - ], - "it-IT": - [ - "Italiano", - "Italian" - ], - "ja-JP": - [ - "日本語", - "Japanese" - ], - "km-KH": - [ - "ភាសាខ្មែរ", - "Khmer" - ], - "ko-KR": - [ - "한국어", - "Korean" - ], - "la": - [ - "Latina", - "Latin" - ], - "lt-LT": - [ - "Lietuvių kalba", - "Lithuanian" - ], - "lv-LV": - [ - "Latviešu", - "Latvian" - ], - "mn-MN": - [ - "Монгол", - "Mongolian" - ], - "nb-NO": - [ - "Norsk bokmål", - "Norwegian (Bokmål)" - ], - "nl-NL": - [ - "Nederlands", - "Dutch" - ], - "nn-NO": - [ - "Norsk nynorsk", - "Norwegian (Nynorsk)" - ], - "pl-PL": - [ - "Polski", - "Polish" - ], - "pt-BR": - [ - "Português (Brasil)", - "Portuguese (Brazil)" - ], - "pt-PT": - [ - "Português (Portugal)", - "Portuguese (Portugal)" - ], - "ro-RO": - [ - "Română", - "Romanian" - ], - "ru-RU": - [ - "Русский", - "Russian" - ], - "sk-SK": - [ - "Slovenčina", - "Slovak" - ], - "sl-SI": - [ - "Slovenščina", - "Slovenian" - ], - "sr-RS": - [ - "Српски / Srpski", - "Serbian" - ], - "sv-SE": - [ - "Svenska", - "Swedish" - ], - "th-TH": - [ - "ไทย", - "Thai" - ], - "tr-TR": - [ - "Türkçe", - "Turkish" - ], - "uk-UA": - [ - "Українська", - "Ukrainian" - ], - "vi-VN": - [ - "Tiếng Việt", - "Vietnamese" - ], - "zh-CN": - [ - "中文 (中国大陆)", - "Chinese (PRC)" - ], - "zh-TW": - [ - "中文 (台灣)", - "Chinese (Taiwan)" - ] -} \ No newline at end of file diff --git a/src/config/memcached.json b/src/config/memcached.json deleted file mode 100644 index c6dd071..0000000 --- a/src/config/memcached.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "port": 11211, - "host": "127.0.0.1", - "namespace": "", - "timeout": 3600 -} \ No newline at end of file diff --git a/src/config/moderators.json b/src/config/moderators.json deleted file mode 100644 index b344d1e..0000000 --- a/src/config/moderators.json +++ /dev/null @@ -1,3 +0,0 @@ -[ - "" -] diff --git a/src/config/nodes.json b/src/config/nodes.json deleted file mode 100644 index 50a40d6..0000000 --- a/src/config/nodes.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "description":"YGGtracker instance #1 running latest stable release", - "url":"http://[201:23b4:991a:634d:8359:4521:5576:15b7]/yggtracker", - "manifest":"http://[201:23b4:991a:634d:8359:4521:5576:15b7]/yggtracker/api/manifest.json" - }, - { - "description":"YGGtracker instance #2 running latest stable release", - "url":"http://[200:e6fd:bb3c:b354:cd3a:f939:753e:cd72]/yggtracker", - "manifest":"http://[200:e6fd:bb3c:b354:cd3a:f939:753e:cd72]/yggtracker/api/manifest.json" - } -] \ No newline at end of file diff --git a/src/config/peers.json b/src/config/peers.json deleted file mode 100644 index abfa9e3..0000000 --- a/src/config/peers.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - { - "description":"YGGtracker public peer instance without traffic limit", - "url":"http://[201:23b4:991a:634d:8359:4521:5576:15b7]/yggstate", - "address":"tls://94.140.114.241:4708" - } -] \ No newline at end of file diff --git a/src/config/sphinx.json b/src/config/sphinx.json deleted file mode 100644 index 6115883..0000000 --- a/src/config/sphinx.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "port":9306, - "host":"127.0.0.1" -} \ No newline at end of file diff --git a/src/config/themes.json b/src/config/themes.json deleted file mode 100644 index a248bb9..0000000 --- a/src/config/themes.json +++ /dev/null @@ -1,3 +0,0 @@ -[ - "default" -] diff --git a/src/config/trackers.json b/src/config/trackers.json deleted file mode 100644 index f4f546c..0000000 --- a/src/config/trackers.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "description":"YGGtracker instance, yggdrasil-only connections", - "url":"http://[201:23b4:991a:634d:8359:4521:5576:15b7]/yggtracker", - "announce":"http://[201:23b4:991a:634d:8359:4521:5576:15b7]:2023/announce", - "stats":"http://[201:23b4:991a:634d:8359:4521:5576:15b7]:2023/stats", - "scrape":"http://[201:23b4:991a:634d:8359:4521:5576:15b7]:2023/scrape" - }, - { - "description":"Yggdrasil-only torrent tracker, operated by jeff", - "url":false, - "announce":"http://[200:1e2f:e608:eb3a:2bf:1e62:87ba:e2f7]/announce", - "stats":"http://[200:1e2f:e608:eb3a:2bf:1e62:87ba:e2f7]/stats", - "scrape":"http://[200:1e2f:e608:eb3a:2bf:1e62:87ba:e2f7]/scrape" - }, - { - "description":"Yggdrasil torrent tracker, operated by R4SAS", - "url":false, - "announce":"http://[316:c51a:62a3:8b9::5]/announce", - "stats":"http://[316:c51a:62a3:8b9::5]/stats", - "scrape":"http://[316:c51a:62a3:8b9::5]/scrape" - } -] \ No newline at end of file diff --git a/src/config/validator.json b/src/config/validator.json deleted file mode 100644 index 73e2931..0000000 --- a/src/config/validator.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "host": - { - "regex": "/^0{0,1}[2-3][a-f0-9]{0,2}:/" - }, - "page": - { - "title": - { - "required": true, - "length": - { - "min": 10, - "max": 255 - }, - "regex": "/.*/ui" - }, - "description": - { - "required": false, - "length": - { - "min": 0, - "max": 10000 - }, - "regex": "/.*/ui" - }, - "keyword": - { - "length": - { - "min": 0, - "max": 140 - }, - "regex": "/[\\w]+/ui" - }, - "keywords": - { - "required": false, - "quantity": - { - "min": 0, - "max": 20 - } - }, - "image": - { - "required": false, - "mime": [ - "image/png", - "image/gif", - "image/jpeg", - "image/webp" - ], - "quantity": - { - "min": 0, - "max": 20 - } - }, - "torrent": - { - "required": true, - "mime": [ - "application/x-bittorrent" - ], - "quantity": - { - "min": 0, - "max": 20 - } - } - } -} diff --git a/src/config/website.json b/src/config/website.json deleted file mode 100644 index 49cfcc0..0000000 --- a/src/config/website.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name":"YGGtracker", - "scheme":"", - "host":"", - "port":"", - "path":"", - "default": - { - "locale":"en-US", - "user": - { - "status": true, - "approved": false - } - }, - "api": - { - "export": - { - "enabled" : true - } - } -} \ No newline at end of file diff --git a/src/crontab/export/feed.php b/src/crontab/export/feed.php deleted file mode 100644 index be41107..0000000 --- a/src/crontab/export/feed.php +++ /dev/null @@ -1,558 +0,0 @@ - [], - 'time' => [ - 'ISO8601' => date('c'), - 'total' => microtime(true), - ], - 'http' => - [ - 'total' => 0, - ], - 'memory' => - [ - 'start' => memory_get_usage(), - 'total' => 0, - 'peaks' => 0 - ], -]; - -// Define public registry -$public = [ - 'user' => [], - 'magnet' => [], -]; - -// Begin export -try -{ - // Init API folder if not exists - @mkdir(__DIR__ . '/../public/api'); - - // Delete cached feeds - @unlink(__DIR__ . '/../public/api/manifest.json'); - - @unlink(__DIR__ . '/../public/api/users.json'); - @unlink(__DIR__ . '/../public/api/magnets.json'); - @unlink(__DIR__ . '/../public/api/magnetComments.json'); - @unlink(__DIR__ . '/../public/api/magnetDownloads.json'); - @unlink(__DIR__ . '/../public/api/magnetStars.json'); - @unlink(__DIR__ . '/../public/api/magnetViews.json'); - - if (API_EXPORT_ENABLED) - { - // Manifest - $manifest = - [ - 'updated' => time(), - 'version' => (string) API_VERSION, - - 'settings' => (object) - [ - 'YGGDRASIL_HOST_REGEX' => (string) YGGDRASIL_HOST_REGEX, - - 'NODE_RULE_SUBJECT' => (string) NODE_RULE_SUBJECT, - 'NODE_RULE_LANGUAGES' => (string) NODE_RULE_LANGUAGES, - - 'USER_DEFAULT_APPROVED' => (bool) USER_DEFAULT_APPROVED, - 'USER_AUTO_APPROVE_ON_MAGNET_APPROVE' => (bool) USER_AUTO_APPROVE_ON_MAGNET_APPROVE, - 'USER_AUTO_APPROVE_ON_COMMENT_APPROVE' => (bool) USER_AUTO_APPROVE_ON_COMMENT_APPROVE, - 'USER_DEFAULT_IDENTICON' => (string) USER_DEFAULT_IDENTICON, - 'USER_IDENTICON_FIELD' => (string) USER_IDENTICON_FIELD, - - 'MAGNET_DEFAULT_APPROVED' => (bool) MAGNET_DEFAULT_APPROVED, - 'MAGNET_DEFAULT_PUBLIC' => (bool) MAGNET_DEFAULT_PUBLIC, - 'MAGNET_DEFAULT_COMMENTS' => (bool) MAGNET_DEFAULT_COMMENTS, - 'MAGNET_DEFAULT_SENSITIVE' => (bool) MAGNET_DEFAULT_SENSITIVE, - - 'MAGNET_EDITOR_LOCK_TIMEOUT' => (int) MAGNET_EDITOR_LOCK_TIMEOUT, - - 'MAGNET_TITLE_MIN_LENGTH' => (int) MAGNET_TITLE_MIN_LENGTH, - 'MAGNET_TITLE_MAX_LENGTH' => (int) MAGNET_TITLE_MAX_LENGTH, - 'MAGNET_TITLE_REGEX' => (string) MAGNET_TITLE_REGEX, - - 'MAGNET_PREVIEW_MIN_LENGTH' => (int) MAGNET_PREVIEW_MIN_LENGTH, - 'MAGNET_PREVIEW_MAX_LENGTH' => (int) MAGNET_PREVIEW_MAX_LENGTH, - 'MAGNET_PREVIEW_REGEX' => (string) MAGNET_PREVIEW_REGEX, - - 'MAGNET_DESCRIPTION_MIN_LENGTH' => (int) MAGNET_DESCRIPTION_MIN_LENGTH, - 'MAGNET_DESCRIPTION_MAX_LENGTH' => (int) MAGNET_DESCRIPTION_MAX_LENGTH, - 'MAGNET_DESCRIPTION_REGEX' => (string) MAGNET_DESCRIPTION_REGEX, - - 'MAGNET_DN_MIN_LENGTH' => (int) MAGNET_DN_MIN_LENGTH, - 'MAGNET_DN_MAX_LENGTH' => (int) MAGNET_DN_MAX_LENGTH, - 'MAGNET_DN_REGEX' => (string) MAGNET_DN_REGEX, - - 'MAGNET_KT_MIN_LENGTH' => (int) MAGNET_KT_MIN_LENGTH, - 'MAGNET_KT_MAX_LENGTH' => (int) MAGNET_KT_MAX_LENGTH, - 'MAGNET_KT_MIN_QUANTITY' => (int) MAGNET_KT_MIN_QUANTITY, - 'MAGNET_KT_MAX_QUANTITY' => (int) MAGNET_KT_MAX_QUANTITY, - 'MAGNET_KT_REGEX' => (string) MAGNET_KT_REGEX, - - 'MAGNET_TR_MIN_QUANTITY' => (int) MAGNET_TR_MIN_QUANTITY, - 'MAGNET_TR_MAX_QUANTITY' => (int) MAGNET_TR_MAX_QUANTITY, - - 'MAGNET_AS_MIN_QUANTITY' => (int) MAGNET_AS_MIN_QUANTITY, - 'MAGNET_AS_MAX_QUANTITY' => (int) MAGNET_AS_MAX_QUANTITY, - - 'MAGNET_WS_MIN_QUANTITY' => (int) MAGNET_WS_MIN_QUANTITY, - 'MAGNET_WS_MAX_QUANTITY' => (int) MAGNET_WS_MAX_QUANTITY, - - 'MAGNET_COMMENT_DEFAULT_APPROVED' => (bool) MAGNET_COMMENT_DEFAULT_APPROVED, - 'MAGNET_COMMENT_DEFAULT_PUBLIC' => (bool) MAGNET_COMMENT_DEFAULT_PUBLIC, - 'MAGNET_COMMENT_DEFAULT_PUBLIC' => (bool) MAGNET_COMMENT_DEFAULT_PUBLIC, - 'MAGNET_COMMENT_MIN_LENGTH' => (int) MAGNET_COMMENT_MIN_LENGTH, - 'MAGNET_COMMENT_MAX_LENGTH' => (int) MAGNET_COMMENT_MAX_LENGTH, - - 'MAGNET_STOP_WORDS_SIMILAR' => (object) MAGNET_STOP_WORDS_SIMILAR, - - 'API_USER_AGENT' => (string) API_USER_AGENT, - - 'API_EXPORT_ENABLED' => (bool) API_EXPORT_ENABLED, - 'API_EXPORT_PUSH_ENABLED' => (bool) API_EXPORT_PUSH_ENABLED, - 'API_EXPORT_USERS_ENABLED' => (bool) API_EXPORT_USERS_ENABLED, - 'API_EXPORT_MAGNETS_ENABLED' => (bool) API_EXPORT_MAGNETS_ENABLED, - 'API_EXPORT_MAGNET_DOWNLOADS_ENABLED' => (bool) API_EXPORT_MAGNET_DOWNLOADS_ENABLED, - 'API_EXPORT_MAGNET_COMMENTS_ENABLED' => (bool) API_EXPORT_MAGNET_COMMENTS_ENABLED, - 'API_EXPORT_MAGNET_STARS_ENABLED' => (bool) API_EXPORT_MAGNET_STARS_ENABLED, - 'API_EXPORT_MAGNET_STARS_ENABLED' => (bool) API_EXPORT_MAGNET_STARS_ENABLED, - 'API_EXPORT_MAGNET_VIEWS_ENABLED' => (bool) API_EXPORT_MAGNET_VIEWS_ENABLED, - - 'API_IMPORT_ENABLED' => (bool) API_IMPORT_ENABLED, - 'API_IMPORT_PUSH_ENABLED' => (bool) API_IMPORT_PUSH_ENABLED, - 'API_IMPORT_USERS_ENABLED' => (bool) API_IMPORT_USERS_ENABLED, - - 'API_IMPORT_USERS_APPROVED_ONLY' => (bool) API_IMPORT_USERS_APPROVED_ONLY, - 'API_IMPORT_MAGNETS_ENABLED' => (bool) API_IMPORT_MAGNETS_ENABLED, - 'API_IMPORT_MAGNETS_APPROVED_ONLY' => (bool) API_IMPORT_MAGNETS_APPROVED_ONLY, - 'API_IMPORT_MAGNET_DOWNLOADS_ENABLED' => (bool) API_IMPORT_MAGNET_DOWNLOADS_ENABLED, - 'API_IMPORT_MAGNET_COMMENTS_ENABLED' => (bool) API_IMPORT_MAGNET_COMMENTS_ENABLED, - 'API_IMPORT_MAGNET_COMMENTS_APPROVED_ONLY' => (bool) API_IMPORT_MAGNET_COMMENTS_APPROVED_ONLY, - 'API_IMPORT_MAGNET_STARS_ENABLED' => (bool) API_IMPORT_MAGNET_STARS_ENABLED, - 'API_IMPORT_MAGNET_VIEWS_ENABLED' => (bool) API_IMPORT_MAGNET_VIEWS_ENABLED, - ], - 'totals' => (object) - [ - 'magnets' => (object) - [ - 'total' => $db->getMagnetsTotal(), - 'distributed' => $db->getMagnetsTotalByUsersPublic(true), - 'local' => $db->getMagnetsTotalByUsersPublic(false), - ], - 'downloads' => (object) - [ - 'total' => $db->getMagnetDownloadsTotal(), - 'distributed' => $db->findMagnetDownloadsTotalByUsersPublic(true), - 'local' => $db->findMagnetDownloadsTotalByUsersPublic(false), - ], - 'comments' => (object) - [ - 'total' => $db->getMagnetCommentsTotal(), - 'distributed' => $db->findMagnetCommentsTotalByUsersPublic(true), - 'local' => $db->findMagnetCommentsTotalByUsersPublic(false), - ], - 'stars' => (object) - [ - 'total' => $db->getMagnetStarsTotal(), - 'distributed' => $db->findMagnetStarsTotalByUsersPublic(true), - 'local' => $db->findMagnetStarsTotalByUsersPublic(false), - ], - 'views' => (object) - [ - 'total' => $db->getMagnetViewsTotal(), - 'distributed' => $db->findMagnetViewsTotalByUsersPublic(true), - 'local' => $db->findMagnetViewsTotalByUsersPublic(false), - ], - ], - 'import' => (object) - [ - 'push' => API_IMPORT_PUSH_ENABLED ? sprintf('%s/api/push.php', WEBSITE_URL) : false, - ], - 'export' => (object) - [ - 'users' => API_EXPORT_USERS_ENABLED ? sprintf('%s/api/users.json', WEBSITE_URL) : false, - 'magnets' => API_EXPORT_MAGNETS_ENABLED ? sprintf('%s/api/magnets.json', WEBSITE_URL) : false, - 'magnetDownloads' => API_EXPORT_MAGNET_DOWNLOADS_ENABLED ? sprintf('%s/api/magnetDownloads.json', WEBSITE_URL) : false, - 'magnetComments' => API_EXPORT_MAGNET_COMMENTS_ENABLED ? sprintf('%s/api/magnetComments.json', WEBSITE_URL) : false, - 'magnetStars' => API_EXPORT_MAGNET_STARS_ENABLED ? sprintf('%s/api/magnetStars.json', WEBSITE_URL) : false, - 'magnetViews' => API_EXPORT_MAGNET_VIEWS_ENABLED ? sprintf('%s/api/magnetViews.json', WEBSITE_URL) : false, - ], - 'trackers' => (object) json_decode(file_get_contents(__DIR__ . '/../../config/trackers.json')), - 'nodes' => (object) json_decode(file_get_contents(__DIR__ . '/../../config/nodes.json')), - 'peers' => (object) json_decode(file_get_contents(__DIR__ . '/../../config/peers.json')), - ]; - - /// Dump feed - if ($handle = fopen(__DIR__ . '/../../public/api/manifest.json', 'w+')) - { - fwrite($handle, json_encode($manifest)); - fclose($handle); - - chmod(__DIR__ . '/../../public/api/manifest.json', 0774); - } - - // Users - if (API_EXPORT_USERS_ENABLED) - { - $users = []; - - foreach ($db->getUsers() as $user) - { - // Dump public data only - if ($user->public) - { - $users[] = (object) - [ - 'userId' => (int) $user->userId, - 'address' => (string) $user->address, - 'timeAdded' => (int) $user->timeAdded, - 'timeUpdated' => (int) $user->timeUpdated, - 'approved' => (bool) $user->approved, - 'magnets' => (int) $db->findMagnetsTotalByUserId($user->userId), - 'downloads' => (int) $db->findMagnetDownloadsTotalByUserId($user->userId), - 'comments' => (int) $db->findMagnetCommentsTotalByUserId($user->userId), - 'stars' => (int) $db->findMagnetStarsTotalByUserId($user->userId), - 'views' => (int) $db->findMagnetViewsTotalByUserId($user->userId), - ]; - } - - // Cache public status - $public['user'][$user->userId] = (bool) $user->public; - } - - /// Dump users feed - if ($handle = fopen(__DIR__ . '/../../public/api/users.json', 'w+')) - { - fwrite($handle, json_encode($users)); - fclose($handle); - - chmod(__DIR__ . '/../../public/api/users.json', 0774); - } - } - - // Magnets - if (API_EXPORT_MAGNETS_ENABLED) - { - $magnets = []; - - foreach ($db->getMagnets($user->userId) as $magnet) - { - // Dump public data only - if ($magnet->public && - $public['user'][$magnet->userId]) // After upgrade, some users have not updated their public status. - // Remote node have warning on import, because user info still hidden to init new profile there. - // Stop magnets export without public profile available, even magnet is public. - { - // Info Hash - $xt = []; - foreach ($db->findMagnetToInfoHashByMagnetId($magnet->magnetId) as $result) - { - if ($infoHash = $db->getInfoHash($result->infoHashId)) - { - $xt[] = (object) [ - 'version' => (float) $infoHash->version, - 'value' => (string) $infoHash->value, - ]; - } - } - - // Keyword Topic - $kt = []; - - foreach ($db->findKeywordTopicByMagnetId($magnet->magnetId) as $result) - { - $kt[] = $db->getKeywordTopic($result->keywordTopicId)->value; - } - - // Address Tracker - $tr = []; - foreach ($db->findAddressTrackerByMagnetId($magnet->magnetId) as $result) - { - $addressTracker = $db->getAddressTracker($result->addressTrackerId); - - $scheme = $db->getScheme($addressTracker->schemeId); - $host = $db->getHost($addressTracker->hostId); - $port = $db->getPort($addressTracker->portId); - $uri = $db->getUri($addressTracker->uriId); - - // Yggdrasil host only - if (!Valid::host($host->value)) - { - continue; - } - - $tr[] = $port->value ? sprintf('%s://%s:%s%s', $scheme->value, - $host->value, - $port->value, - $uri->value) : sprintf('%s://%s%s', $scheme->value, - $host->value, - $uri->value); - } - - // Acceptable Source - $as = []; - - foreach ($db->findAcceptableSourceByMagnetId($magnet->magnetId) as $result) - { - $acceptableSource = $db->getAcceptableSource($result->acceptableSourceId); - - $scheme = $db->getScheme($acceptableSource->schemeId); - $host = $db->getHost($acceptableSource->hostId); - $port = $db->getPort($acceptableSource->portId); - $uri = $db->getUri($acceptableSource->uriId); - - // Yggdrasil host only - if (!Valid::host($host->value)) - { - continue; - } - - $as[] = $port->value ? sprintf('%s://%s:%s%s', $scheme->value, - $host->value, - $port->value, - $uri->value) : sprintf('%s://%s%s', $scheme->value, - $host->value, - $uri->value); - } - - // Exact Source - $xs = []; - - foreach ($db->findExactSourceByMagnetId($magnet->magnetId) as $result) - { - $eXactSource = $db->getExactSource($result->eXactSourceId); - - $scheme = $db->getScheme($eXactSource->schemeId); - $host = $db->getHost($eXactSource->hostId); - $port = $db->getPort($eXactSource->portId); - $uri = $db->getUri($eXactSource->uriId); - - // Yggdrasil host only - if (!Valid::host($host->value)) - { - continue; - } - - $xs[] = $port->value ? sprintf('%s://%s:%s%s', $scheme->value, - $host->value, - $port->value, - $uri->value) : sprintf('%s://%s%s', $scheme->value, - $host->value, - $uri->value); - } - - $magnets[] = (object) - [ - 'magnetId' => (int) $magnet->magnetId, - 'userId' => (int) $magnet->userId, - 'title' => (string) $magnet->title, - 'preview' => (string) $magnet->preview, - 'description' => (string) $magnet->description, - 'comments' => (bool) $magnet->comments, - 'sensitive' => (bool) $magnet->sensitive, - 'approved' => (bool) $magnet->approved, - 'timeAdded' => (int) $magnet->timeAdded, - 'timeUpdated' => (int) $magnet->timeUpdated, - 'dn' => (string) $magnet->dn, - 'xl' => (float) $magnet->xl, - 'xt' => (object) $xt, - 'kt' => (object) $kt, - 'tr' => (object) $tr, - 'as' => (object) $as, - 'xs' => (object) $xs, - ]; - } - - // Cache public status - if (!empty($public['user'][$magnet->userId])) - { - $public['magnet'][$magnet->magnetId] = (bool) $magnet->public; - } else { - $public['magnet'][$magnet->magnetId] = false; - } - } - - /// Dump magnets feed - if ($handle = fopen(__DIR__ . '/../../public/api/magnets.json', 'w+')) - { - fwrite($handle, json_encode($magnets)); - fclose($handle); - - chmod(__DIR__ . '/../../public/api/magnets.json', 0774); - } - } - - // Magnet downloads - if (API_EXPORT_MAGNET_DOWNLOADS_ENABLED) - { - $magnetDownloads = []; - - foreach ($db->getMagnetDownloads() as $magnetDownload) - { - // Dump public data only - if (!empty($public['magnet'][$magnetDownload->magnetId]) && - !empty($public['user'][$magnetDownload->userId])) - { - $magnetDownloads[] = (object) - [ - 'magnetDownloadId' => (int) $magnetDownload->magnetDownloadId, - 'userId' => (int) $magnetDownload->userId, - 'magnetId' => (int) $magnetDownload->magnetId, - 'timeAdded' => (int) $magnetDownload->timeAdded, - ]; - } - } - - /// Dump feed - if ($handle = fopen(__DIR__ . '/../../public/api/magnetDownloads.json', 'w+')) - { - fwrite($handle, json_encode($magnetDownloads)); - fclose($handle); - - chmod(__DIR__ . '/../../public/api/magnetDownloads.json', 0774); - } - } - - // Magnet comments - if (API_EXPORT_MAGNET_COMMENTS_ENABLED) - { - $magnetComments = []; - - foreach ($db->getMagnetComments() as $magnetComment) - { - // Dump public data only - if (!empty($public['magnet'][$magnetComment->magnetId]) && - !empty($public['user'][$magnetComment->userId])) - { - $magnetComments[] = (object) - [ - 'magnetCommentId' => (int) $magnetComment->magnetCommentId, - 'magnetCommentIdParent' => $magnetComment->magnetCommentIdParent, - 'userId' => (int) $magnetComment->userId, - 'magnetId' => (int) $magnetComment->magnetId, - 'timeAdded' => (int) $magnetComment->timeAdded, - 'approved' => (bool) $magnetComment->approved, - 'value' => (string) $magnetComment->value - ]; - } - } - - /// Dump feed - if ($handle = fopen(__DIR__ . '/../../public/api/magnetComments.json', 'w+')) - { - fwrite($handle, json_encode($magnetComments)); - fclose($handle); - - chmod(__DIR__ . '/../../public/api/magnetComments.json', 0774); - } - } - - // Magnet stars - if (API_EXPORT_MAGNET_STARS_ENABLED) - { - $magnetStars = []; - - foreach ($db->getMagnetStars() as $magnetStar) - { - // Dump public data only - if (!empty($public['magnet'][$magnetStar->magnetId]) && - !empty($public['user'][$magnetStar->userId])) - { - $magnetStars[] = (object) - [ - 'magnetStarId' => (int) $magnetStar->magnetStarId, - 'userId' => (int) $magnetStar->userId, - 'magnetId' => (int) $magnetStar->magnetId, - 'value' => (bool) $magnetStar->value, - 'timeAdded' => (int) $magnetStar->timeAdded, - ]; - } - } - - /// Dump feed - if ($handle = fopen(__DIR__ . '/../../public/api/magnetStars.json', 'w+')) - { - fwrite($handle, json_encode($magnetStars)); - fclose($handle); - - chmod(__DIR__ . '/../../public/api/magnetStars.json', 0774); - } - } - - // Magnet views - if (API_EXPORT_MAGNET_VIEWS_ENABLED) - { - $magnetViews = []; - - foreach ($db->getMagnetViews() as $magnetView) - { - // Dump public data only - if (!empty($public['magnet'][$magnetView->magnetId]) && - !empty($public['user'][$magnetView->userId])) - { - $magnetViews[] = (object) - [ - 'magnetViewId' => (int) $magnetView->magnetViewId, - 'userId' => (int) $magnetView->userId, - 'magnetId' => (int) $magnetView->magnetId, - 'timeAdded' => (int) $magnetView->timeAdded, - ]; - } - } - - /// Dump feed - if ($handle = fopen(__DIR__ . '/../../public/api/magnetViews.json', 'w+')) - { - fwrite($handle, json_encode($magnetViews)); - fclose($handle); - - chmod(__DIR__ . '/../../public/api/magnetViews.json', 0774); - } - } - } - -} catch (EXception $e) { - - var_dump($e); -} - -// Debug output -$debug['time']['total'] = microtime(true) - $debug['time']['total']; - -$debug['memory']['total'] = memory_get_usage() - $debug['memory']['start']; -$debug['memory']['peaks'] = memory_get_peak_usage(); - -$debug['db']['total']['select'] = $db->getDebug()->query->select->total; -$debug['db']['total']['insert'] = $db->getDebug()->query->insert->total; -$debug['db']['total']['update'] = $db->getDebug()->query->update->total; -$debug['db']['total']['delete'] = $db->getDebug()->query->delete->total; - -print_r($debug); - -// Debug log -if (LOG_CRONTAB_EXPORT_FEED_ENABLED) -{ - @mkdir(LOG_DIRECTORY, 0774, true); - - if ($handle = fopen(LOG_DIRECTORY . '/' . LOG_CRONTAB_EXPORT_FEED_FILENAME, 'a+')) - { - fwrite($handle, print_r($debug, true)); - fclose($handle); - - chmod(LOG_DIRECTORY . '/' . LOG_CRONTAB_EXPORT_FEED_FILENAME, 0774); - } -} \ No newline at end of file diff --git a/src/crontab/export/push.php b/src/crontab/export/push.php deleted file mode 100644 index 18ae4e2..0000000 --- a/src/crontab/export/push.php +++ /dev/null @@ -1,506 +0,0 @@ - [], - 'time' => [ - 'ISO8601' => date('c'), - 'total' => microtime(true), - ], - 'http' => - [ - 'total' => 0, - ], - 'memory' => - [ - 'start' => memory_get_usage(), - 'total' => 0, - 'peaks' => 0 - ], -]; - -// Define public registry -$public = [ - 'user' => [], - 'magnet' => [], -]; - -// Push export enabled -if (API_EXPORT_PUSH_ENABLED) -{ - // Get push queue from memory pool - foreach((array) $memoryApiExportPush = $memory->get('api.export.push') as $id => $push) - { - // Init request - $request = []; - - // User request - if (!empty($push->userId) && API_EXPORT_USERS_ENABLED) - { - // Get user info - if ($user = $db->getUser($push->userId)) - { - // Dump public data only - if ($user->public) - { - $request['user'] = (object) - [ - 'userId' => (int) $user->userId, - 'address' => (string) $user->address, - 'timeAdded' => (int) $user->timeAdded, - 'timeUpdated' => (int) $user->timeUpdated, - 'approved' => (bool) $user->approved, - ]; - - // Cache public status - $public['user'][$user->userId] = (bool) $user->public; - } - } - } - - // Magnet request - if (!empty($push->magnetId) && API_EXPORT_MAGNETS_ENABLED) - { - // Get magnet info - if ($magnet = $db->getMagnet($push->magnetId)) - { - if ($magnet->public && - $public['user'][$magnet->userId]) // After upgrade, some users have not updated their public status. - // Remote node have warning on import, because user info still hidden to init new profile there. - // Stop magnets export without public profile available, even magnet is public. - { - // Info Hash - $xt = []; - foreach ($db->findMagnetToInfoHashByMagnetId($magnet->magnetId) as $result) - { - if ($infoHash = $db->getInfoHash($result->infoHashId)) - { - $xt[] = (object) [ - 'version' => (float) $infoHash->version, - 'value' => (string) $infoHash->value, - ]; - } - } - - // Keyword Topic - $kt = []; - - foreach ($db->findKeywordTopicByMagnetId($magnet->magnetId) as $result) - { - $kt[] = $db->getKeywordTopic($result->keywordTopicId)->value; - } - - // Address Tracker - $tr = []; - foreach ($db->findAddressTrackerByMagnetId($magnet->magnetId) as $result) - { - $addressTracker = $db->getAddressTracker($result->addressTrackerId); - - $scheme = $db->getScheme($addressTracker->schemeId); - $host = $db->getHost($addressTracker->hostId); - $port = $db->getPort($addressTracker->portId); - $uri = $db->getUri($addressTracker->uriId); - - // Yggdrasil host only - if (!Valid::host($host->value)) - { - continue; - } - - $tr[] = $port->value ? sprintf('%s://%s:%s%s', $scheme->value, - $host->value, - $port->value, - $uri->value) : sprintf('%s://%s%s', $scheme->value, - $host->value, - $uri->value); - } - - // Acceptable Source - $as = []; - - foreach ($db->findAcceptableSourceByMagnetId($magnet->magnetId) as $result) - { - $acceptableSource = $db->getAcceptableSource($result->acceptableSourceId); - - $scheme = $db->getScheme($acceptableSource->schemeId); - $host = $db->getHost($acceptableSource->hostId); - $port = $db->getPort($acceptableSource->portId); - $uri = $db->getUri($acceptableSource->uriId); - - // Yggdrasil host only - if (!Valid::host($host->value)) - { - continue; - } - - $as[] = $port->value ? sprintf('%s://%s:%s%s', $scheme->value, - $host->value, - $port->value, - $uri->value) : sprintf('%s://%s%s', $scheme->value, - $host->value, - $uri->value); - } - - // Exact Source - $xs = []; - - foreach ($db->findExactSourceByMagnetId($magnet->magnetId) as $result) - { - $eXactSource = $db->getExactSource($result->eXactSourceId); - - $scheme = $db->getScheme($eXactSource->schemeId); - $host = $db->getHost($eXactSource->hostId); - $port = $db->getPort($eXactSource->portId); - $uri = $db->getUri($eXactSource->uriId); - - // Yggdrasil host only - if (!Valid::host($host->value)) - { - continue; - } - - $xs[] = $port->value ? sprintf('%s://%s:%s%s', $scheme->value, - $host->value, - $port->value, - $uri->value) : sprintf('%s://%s%s', $scheme->value, - $host->value, - $uri->value); - } - - $request['magnet'] = (object) - [ - 'magnetId' => (int) $magnet->magnetId, - 'userId' => (int) $magnet->userId, - 'title' => (string) $magnet->title, - 'preview' => (string) $magnet->preview, - 'description' => (string) $magnet->description, - 'comments' => (bool) $magnet->comments, - 'sensitive' => (bool) $magnet->sensitive, - 'approved' => (bool) $magnet->approved, - 'timeAdded' => (int) $magnet->timeAdded, - 'timeUpdated' => (int) $magnet->timeUpdated, - 'dn' => (string) $magnet->dn, - 'xl' => (float) $magnet->xl, - 'xt' => (object) $xt, - 'kt' => (object) $kt, - 'tr' => (object) $tr, - 'as' => (object) $as, - 'xs' => (object) $xs, - ]; - } - - // Cache public status - if (!empty($public['user'][$magnet->userId])) - { - $public['magnet'][$magnet->magnetId] = (bool) $magnet->public; - } else { - $public['magnet'][$magnet->magnetId] = false; - } - } - } - - // Magnet download request - if (!empty($push->magnetDownloadId) && API_EXPORT_MAGNET_DOWNLOADS_ENABLED) - { - // Get magnet download info - if ($magnetDownload = $db->getMagnetDownload($push->magnetDownloadId)) - { - // Dump public data only - if (!empty($public['magnet'][$magnetDownload->magnetId]) && - !empty($public['user'][$magnetDownload->userId])) - { - $request['magnetDownload'] = (object) - [ - 'magnetDownloadId' => (int) $magnetDownload->magnetDownloadId, - 'userId' => (int) $magnetDownload->userId, - 'magnetId' => (int) $magnetDownload->magnetId, - 'timeAdded' => (int) $magnetDownload->timeAdded, - ]; - } - } - } - - // Magnet comment request - if (!empty($push->magnetCommentId) && API_EXPORT_MAGNET_COMMENTS_ENABLED) - { - // Get magnet comment info - if ($magnetComment = $db->getMagnetComment($push->magnetCommentId)) - { - // Dump public data only - if (!empty($public['magnet'][$magnetComment->magnetId]) && - !empty($public['user'][$magnetComment->userId])) - { - $request['magnetComment'] = (object) - [ - 'magnetCommentId' => (int) $magnetComment->magnetCommentId, - 'magnetCommentIdParent' => (int) $magnetComment->magnetCommentIdParent, - 'userId' => (int) $magnetComment->userId, - 'magnetId' => (int) $magnetComment->magnetId, - 'timeAdded' => (int) $magnetComment->timeAdded, - 'approved' => (bool) $magnetComment->approved, - 'value' => (string) $magnetComment->value - ]; - } - } - } - - // Magnet star request - if (!empty($push->magnetStarId) && API_EXPORT_MAGNET_STARS_ENABLED) - { - // Get magnet star info - if ($magnetStar = $db->getMagnetStar($push->magnetStarId)) - { - // Dump public data only - if (!empty($public['magnet'][$magnetStar->magnetId]) && - !empty($public['user'][$magnetStar->userId])) - { - $request['magnetStar'] = (object) - [ - 'magnetStarId' => (int) $magnetStar->magnetStarId, - 'userId' => (int) $magnetStar->userId, - 'magnetId' => (int) $magnetStar->magnetId, - 'value' => (bool) $magnetStar->value, - 'timeAdded' => (int) $magnetStar->timeAdded, - ]; - } - } - } - - // Magnet view request - if (!empty($push->magnetViewId) && API_EXPORT_MAGNET_VIEWS_ENABLED) - { - // Get magnet view info - if ($magnetView = $db->getMagnetView($push->magnetViewId)) - { - // Dump public data only - if (!empty($public['magnet'][$magnetView->magnetId]) && - !empty($public['user'][$magnetView->userId])) - { - $request['magnetView'] = (object) - [ - 'magnetViewId' => (int) $magnetView->magnetViewId, - 'userId' => (int) $magnetView->userId, - 'magnetId' => (int) $magnetView->magnetId, - 'timeAdded' => (int) $magnetView->timeAdded, - ]; - } - } - } - - // Check request - if (empty($request)) - { - // Amy request data match conditions, skip - - continue; - } - - // Send push data - foreach (json_decode( - file_get_contents(__DIR__ . '/../../config/nodes.json') - ) as $node) - { - // Manifest exists - if (empty($node->manifest)) - { - $debug['dump']['warning'][] = sprintf( - _('Manifest URL not provided: %s'), - $node - ); - - continue; - } - - // Skip non-condition addresses - $error = []; - - if (!Valid::url($node->manifest, $error)) - { - $debug['dump'][$node->manifest]['warning'][] = sprintf( - _('Manifest URL invalid: %s'), - print_r( - $error, - true - ) - ); - - continue; - } - - // Skip current host - $thisUrl = Yggverse\Parser\Url::parse(WEBSITE_URL); - $manifestUrl = Yggverse\Parser\Url::parse($node->manifest); - - if (empty($thisUrl->host->name) || - empty($manifestUrl->host->name) || - $manifestUrl->host->name == $thisUrl->host->name) // @TODO some mirrors could be available, improve condition - { - // No debug warnings in this case, continue next item - - continue; - } - - // Get node manifest - // @TODO cache to prevent extra-queries as usually this script running every minute - $curl = new Curl($node->manifest, API_USER_AGENT); - - $debug['http']['total']++; - - if (200 != $code = $curl->getCode()) - { - $debug['dump'][$node->manifest]['warning'][] = sprintf( - _('Manifest unreachable with code: "%s"'), - $code - ); - - continue; - } - - if (!$manifest = $curl->getResponse()) - { - $debug['dump'][$node->manifest]['warning'][] = sprintf( - _('Manifest URL "%s" has broken response'), - $node->manifest - ); - - continue; - } - - // API channel not exists - if (empty($manifest->import)) - { - $debug['dump'][$node->manifest]['warning'][] = sprintf( - _('Manifest import URL not provided: %s'), - $node - ); - - continue; - } - - // Push API channel not exists - if (empty($manifest->import->push)) - { - $debug['dump'][$manifest->import->push]['warning'][] = sprintf( - _('Manifest import push URL not provided: %s'), - $node - ); - - continue; - } - - // Skip sending to non-condition addresses - $error = []; - - if (!Valid::url($manifest->import->push, $error)) - { - $debug['dump'][$manifest->import->push]['warning'][] = sprintf( - _('Manifest import push URL invalid: %s'), - print_r( - $error, - true - ) - ); - - continue; - } - - // Skip current host - $thisUrl = Yggverse\Parser\Url::parse(WEBSITE_URL); - $pushUrl = Yggverse\Parser\Url::parse($manifest->import->push); - - if (empty($thisUrl->host->name) || - empty($pushUrl->host->name) || - $pushUrl->host->name == $thisUrl->host->name) // @TODO some mirrors could be available, improve condition - { - // No debug warnings in this case, continue next item - - continue; - } - - // @TODO add recipient manifest conditions check to not disturb it API without needs - - // Send push request - $debug['dump'][$manifest->import->push]['request'][] = $request; - - $curl = new Curl( - $manifest->import->push, - API_USER_AGENT, - [ - 'data' => json_encode($request) - ] - ); - - $debug['http']['total']++; - - if (200 != $code = $curl->getCode()) - { - $debug['dump'][$manifest->import->push]['warning'][] = sprintf( - _('Server returned code "%s"'), - $code - ); - - continue; - } - - if (!$response = $curl->getResponse()) - { - $debug['dump'][$manifest->import->push]['warning'][] = _('Could not receive server response'); - - continue; - } - - $debug['dump'][$manifest->import->push]['response'][] = $response; - } - - // Drop processed item from queue - unset($memoryApiExportPush[$id]); - } - - // Update memory pool - $memory->set('api.export.push', $memoryApiExportPush, 3600); -} - -// Export push disabled, free api.export.push pool -else -{ - $memory->delete('api.export.push'); -} - -// Debug output -$debug['time']['total'] = microtime(true) - $debug['time']['total']; - -$debug['memory']['total'] = memory_get_usage() - $debug['memory']['start']; -$debug['memory']['peaks'] = memory_get_peak_usage(); - -$debug['db']['total']['select'] = $db->getDebug()->query->select->total; -$debug['db']['total']['insert'] = $db->getDebug()->query->insert->total; -$debug['db']['total']['update'] = $db->getDebug()->query->update->total; -$debug['db']['total']['delete'] = $db->getDebug()->query->delete->total; - -print_r($debug); - -// Debug log -if (LOG_CRONTAB_EXPORT_PUSH_ENABLED) -{ - @mkdir(LOG_DIRECTORY, 0770, true); - - if ($handle = fopen(LOG_DIRECTORY . '/' . LOG_CRONTAB_EXPORT_PUSH_FILENAME, 'a+')) - { - fwrite($handle, print_r($debug, true)); - fclose($handle); - - chmod(LOG_DIRECTORY . '/' . LOG_CRONTAB_EXPORT_PUSH_FILENAME, 0770); - } -} \ No newline at end of file diff --git a/src/crontab/import/feed.php b/src/crontab/import/feed.php deleted file mode 100644 index 0cefd3b..0000000 --- a/src/crontab/import/feed.php +++ /dev/null @@ -1,1193 +0,0 @@ - [], - 'time' => - [ - 'ISO8601' => date('c'), - 'total' => microtime(true), - ], - 'http' => - [ - 'total' => 0, - ], - 'memory' => - [ - 'start' => memory_get_usage(), - 'total' => 0, - 'peaks' => 0 - ], - 'db' => - [ - 'total' => [ - 'select' => 0, - 'insert' => 0, - 'update' => 0, - 'delete' => 0, - ] - ], -]; - -// Begin import -try -{ - // Transaction begin - $db->beginTransaction(); - - foreach (json_decode( - file_get_contents(__DIR__ . '/../../config/nodes.json') - ) as $node) - { - // Manifest exists - if (empty($node->manifest)) - { - array_push( - $debug['dump'], - sprintf( - _('Manifest URL not provided for this node: %s'), - $node - ) - ); - - continue; - } - - // Skip non-condition addresses - $error = []; - - if (!Valid::url($node->manifest, $error)) - { - array_push( - $debug['dump'], - sprintf( - _('Manifest URL "%s" invalid: %s'), - $node->manifest, - print_r( - $error, - true - ) - ) - ); - - continue; - } - - // Skip current host - $thisUrl = Yggverse\Parser\Url::parse(WEBSITE_URL); - $manifestUrl = Yggverse\Parser\Url::parse($node->manifest); - - if (empty($thisUrl->host->name) || - empty($manifestUrl->host->name) || - $manifestUrl->host->name == $thisUrl->host->name) // @TODO some mirrors could be available, improve condition - { - // No debug warnings in this case, continue next item - - continue; - } - - // Get node manifest - $curl = new Curl($node->manifest, API_USER_AGENT); - - $debug['http']['total']++; - - if (200 != $code = $curl->getCode()) - { - array_push( - $debug['dump'], - sprintf( - _('Manifest URL "%s" unreachable with code: "%s"'), - $node->manifest, - $code - ) - ); - - continue; - } - - if (!$manifest = $curl->getResponse()) - { - array_push( - $debug['dump'], - sprintf( - _('Manifest URL "%s" has broken response'), - $node->manifest - ) - ); - - continue; - } - - if (empty($manifest->version) || $manifest->version !== API_VERSION) - { - array_push( - $debug['dump'], - sprintf( - _('Manifest API not compatible with local version "%s"'), - API_VERSION - ) - ); - - continue; - } - - if (empty($manifest->export)) - { - array_push( - $debug['dump'], - sprintf( - _('Manifest URL "%s" has broken protocol'), - $node->manifest - ) - ); - - continue; - } - - // Users - if (API_IMPORT_USERS_ENABLED) - { - $error = []; - - if (!Valid::url($manifest->export->users, $error)) - { - array_push( - $debug['dump'], - sprintf( - _('Users feed URL "%s" invalid: %s'), - $manifest->export->users, - print_r( - $error, - true - ) - ) - ); - - continue; - } - - // Call feed - $curl = new Curl($manifest->export->users, API_USER_AGENT); - - $debug['http']['total']++; - - if (200 != $code = $curl->getCode()) - { - array_push( - $debug['dump'], - sprintf( - _('Users feed URL "%s" unreachable with code: "%s"'), - $manifest->export->users, - $code - ) - ); - - continue; - } - - if (!$remoteUsers = $curl->getResponse()) - { - array_push( - $debug['dump'], - sprintf( - _('Users feed URL "%s" has broken response'), - $manifest->export->users - ) - ); - - continue; - } - - // Init alias registry for this host - $aliasUserId = []; - - foreach ((object) $remoteUsers as $remoteUser) - { - // Validate required fields - $error = []; - - if (!Valid::user($remoteUser, $error)) - { - array_push( - $debug['dump'], - sprintf( - _('Users feed URL "%s" has invalid protocol: "%s" error: "%s"'), - $manifest->export->users, - print_r( - $remoteUser, - true - ), - print_r( - $error, - true - ) - ) - ); - - continue; - } - - // Skip import on user approved required - if (API_IMPORT_USERS_APPROVED_ONLY && !$remoteUser->approved) - { - // No debug warnings in this case, continue next item - - continue; - } - - // Init session - else if (!$localUser = $db->getUser( - $db->initUserId( - $remoteUser->address, - USER_AUTO_APPROVE_ON_IMPORT_APPROVED ? $remoteUser->approved : USER_DEFAULT_APPROVED, - $remoteUser->timeAdded - ) - )) - { - array_push( - $debug['dump'], - sprintf( - _('Could not init user with address "%s" using feed URL "%s"'), - $remoteUser->address, - $manifest->export->users - ) - ); - - continue; - } - - // Update time added if newer - if ($localUser->timeAdded < $remoteUser->timeAdded) - { - $db->updateUserTimeAdded( - $localUser->userId, - $remoteUser->timeAdded - ); - } - - // Update user info if newer - if ($localUser->timeUpdated < $remoteUser->timeUpdated) - { - // Update time updated - $db->updateUserTimeUpdated( - $localUser->userId, - $remoteUser->timeUpdated - ); - - // Update approved for existing user - if (USER_AUTO_APPROVE_ON_IMPORT_APPROVED && $localUser->approved !== $remoteUser->approved && $remoteUser->approved) - { - $db->updateUserApproved( - $localUser->userId, - $remoteUser->approved, - $remoteUser->timeUpdated - ); - } - - // Set public as received remotely - if (!$localUser->public) - { - $db->updateUserPublic( - $localUser->userId, - true, - $remoteUser->timeUpdated - ); - } - } - - // Register userId alias - $aliasUserId[$remoteUser->userId] = $localUser->userId; - } - - // Magnets - if (API_IMPORT_MAGNETS_ENABLED) - { - $error = []; - - if (!Valid::url($manifest->export->magnets, $error)) - { - array_push( - $debug['dump'], - sprintf( - _('Magnets feed URL "%s" invalid: %s'), - $manifest->export->magnets, - print_r( - $error, - true - ) - ) - ); - - continue; - } - - // Call feed - $curl = new Curl($manifest->export->magnets, API_USER_AGENT); - - $debug['http']['total']++; - - if (200 != $code = $curl->getCode()) - { - array_push( - $debug['dump'], - sprintf( - _('Magnets feed URL "%s" unreachable with code: "%s"'), - $manifest->export->magnets, - $code - ) - ); - - continue; - } - - if (!$remoteMagnets = $curl->getResponse()) - { - array_push( - $debug['dump'], - sprintf( - _('Magnets feed URL "%s" has broken response'), - $manifest->export->magnets - ) - ); - - continue; - } - - // Init alias registry for this host - $aliasMagnetId = []; - - foreach ((object) $remoteMagnets as $remoteMagnet) - { - // Validate required fields by protocol - $error = []; - - if (!Valid::magnet($remoteMagnet, $error)) - { - array_push( - $debug['dump'], - sprintf( - _('Magnets feed URL "%s" has invalid protocol: "%s" error: "%s"'), - $manifest->export->magnets, - print_r( - $remoteMagnet, - true - ), - print_r( - $error, - true - ) - ) - ); - - continue; - } - - // Aliases check - if (!isset($aliasUserId[$remoteMagnet->userId])) - { - array_push( - $debug['dump'], - sprintf( - _('Local alias for remote userId "%s" not found in URL "%s" %s'), - $remoteMagnet->userId, - $manifest->export->magnets, - print_r( - $remoteMagnet, - true - ), - ) - ); - - continue; - } - - // Skip import on magnet approved required - if (API_IMPORT_MAGNETS_APPROVED_ONLY && !$remoteMagnet->approved) - { - // No debug warnings in this case, continue next item - - continue; - } - - // Add new magnet if not exist by timestamp added for this user - if (!$localMagnet = $db->findMagnet($aliasUserId[$remoteMagnet->userId], $remoteMagnet->timeAdded)) - { - $localMagnet = $db->getMagnet( - $db->addMagnet( - $aliasUserId[$remoteMagnet->userId], - $remoteMagnet->xl, - $remoteMagnet->dn, - '', // @TODO linkSource used for debug only, will be deleted later - true, - $remoteMagnet->comments, - $remoteMagnet->sensitive, - MAGNET_AUTO_APPROVE_ON_IMPORT_APPROVED ? $remoteMagnet->approved : MAGNET_DEFAULT_APPROVED, - $remoteMagnet->timeAdded - ) - ); - } - - // Update time added if newer - if ($localMagnet->timeAdded < $remoteMagnet->timeAdded) - { - $db->updateMagnetTimeAdded( - $localMagnet->magnetId, - $remoteMagnet->timeAdded - ); - } - - // Update info if remote newer - if ($localMagnet->timeUpdated < $remoteMagnet->timeUpdated) - { - // Magnet fields - $db->updateMagnetXl($localMagnet->magnetId, $remoteMagnet->xl, $remoteMagnet->timeUpdated); - $db->updateMagnetDn($localMagnet->magnetId, $remoteMagnet->dn, $remoteMagnet->timeUpdated); - $db->updateMagnetTitle($localMagnet->magnetId, $remoteMagnet->title, $remoteMagnet->timeUpdated); - $db->updateMagnetPreview($localMagnet->magnetId, $remoteMagnet->preview, $remoteMagnet->timeUpdated); - $db->updateMagnetDescription($localMagnet->magnetId, $remoteMagnet->description, $remoteMagnet->timeUpdated); - $db->updateMagnetComments($localMagnet->magnetId, $remoteMagnet->comments, $remoteMagnet->timeUpdated); - $db->updateMagnetSensitive($localMagnet->magnetId, $remoteMagnet->sensitive, $remoteMagnet->timeUpdated); - - if (MAGNET_AUTO_APPROVE_ON_IMPORT_APPROVED && $localMagnet->approved !== $remoteMagnet->approved && $remoteMagnet->approved) - { - $db->updateMagnetApproved($localMagnet->magnetId, $remoteMagnet->approved, $remoteMagnet->timeUpdated); - } - - // xt - foreach ((array) $remoteMagnet->xt as $xt) - { - switch ($xt->version) - { - case 1: - - $exist = false; - - foreach ($db->findMagnetToInfoHashByMagnetId($localMagnet->magnetId) as $result) - { - if ($infoHash = $db->getInfoHash($result->infoHashId)) - { - if ($infoHash->version == 1) - { - $exist = true; - } - } - } - - if (!$exist) - { - $db->addMagnetToInfoHash( - $localMagnet->magnetId, - $db->initInfoHashId( - $xt->value, 1 - ) - ); - } - - break; - - case 2: - - $exist = false; - - foreach ($db->findMagnetToInfoHashByMagnetId($localMagnet->magnetId) as $result) - { - if ($infoHash = $db->getInfoHash($result->infoHashId)) - { - if ($infoHash->version == 2) - { - $exist = true; - } - } - } - - if (!$exist) - { - $db->addMagnetToInfoHash( - $localMagnet->magnetId, - $db->initInfoHashId( - $xt->value, 2 - ) - ); - } - - break; - } - } - - // kt - $db->deleteMagnetToKeywordTopicByMagnetId($localMagnet->magnetId); - - foreach ($remoteMagnet->kt as $kt) - { - $db->initMagnetToKeywordTopicId( - $localMagnet->magnetId, - $db->initKeywordTopicId(trim(mb_strtolower($kt))) // @TODO - ); - } - - // tr - $db->deleteMagnetToAddressTrackerByMagnetId($localMagnet->magnetId); - - foreach ($remoteMagnet->tr as $tr) - { - if ($url = Yggverse\Parser\Url::parse($tr)) - { - $db->initMagnetToAddressTrackerId( - $localMagnet->magnetId, - $db->initAddressTrackerId( - $db->initSchemeId($url->host->scheme), - $db->initHostId($url->host->name), - $db->initPortId($url->host->port), - $db->initUriId($url->page->uri) - ) - ); - } - } - - // as - $db->deleteMagnetToAcceptableSourceByMagnetId($localMagnet->magnetId); - - foreach ($remoteMagnet->as as $as) - { - if ($url = Yggverse\Parser\Url::parse($as)) - { - $db->initMagnetToAcceptableSourceId( - $localMagnet->magnetId, - $db->initAcceptableSourceId( - $db->initSchemeId($url->host->scheme), - $db->initHostId($url->host->name), - $db->initPortId($url->host->port), - $db->initUriId($url->page->uri) - ) - ); - } - } - - // xs - $db->deleteMagnetToExactSourceByMagnetId($localMagnet->magnetId); - - foreach ($remoteMagnet->xs as $xs) - { - if ($url = Yggverse\Parser\Url::parse($xs)) - { - $db->initMagnetToExactSourceId( - $localMagnet->magnetId, - $db->initExactSourceId( - $db->initSchemeId($url->host->scheme), - $db->initHostId($url->host->name), - $db->initPortId($url->host->port), - $db->initUriId($url->page->uri) - ) - ); - } - } - } - - // Add magnet alias for this host - $aliasMagnetId[$remoteMagnet->magnetId] = $localMagnet->magnetId; - } - - // Magnet comments - if (API_IMPORT_MAGNET_COMMENTS_ENABLED) - { - $error = []; - - if (!Valid::url($manifest->export->magnetComments, $error)) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet comments feed URL "%s" invalid: %s'), - $manifest->export->magnetComments, - print_r( - $error, - true - ) - ) - ); - - continue; - } - - // Call feed - $curl = new Curl($manifest->export->magnetComments, API_USER_AGENT); - - $debug['http']['total']++; - - if (200 != $code = $curl->getCode()) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet comments feed URL "%s" unreachable with code: "%s"'), - $manifest->export->magnetComments, - $code - ) - ); - - continue; - } - - if (!$remoteMagnetComments = $curl->getResponse()) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet comments feed URL "%s" has broken response'), - $manifest->export->magnetComments - ) - ); - - continue; - } - - foreach ((object) $remoteMagnetComments as $remoteMagnetComment) - { - // Validate - $error = []; - - if (!Valid::magnetComment($remoteMagnetComment, $error)) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet comments feed URL "%s" has invalid protocol: "%s" error: "%s"'), - $manifest->export->magnetComments, - print_r( - $remoteMagnetComment, - true - ), - print_r( - $error, - true - ) - ) - ); - - continue; - } - - // Aliases check - if (!isset($aliasUserId[$remoteMagnetComment->userId])) - { - array_push( - $debug['dump'], - sprintf( - _('Local alias for remote userId "%s" not found in URL "%s" %s'), - $remoteMagnetComment->userId, - $manifest->export->magnetComments, - print_r( - $remoteMagnetComment, - true - ), - ) - ); - - continue; - } - - if (!isset($aliasMagnetId[$remoteMagnetComment->magnetId])) - { - array_push( - $debug['dump'], - sprintf( - _('Local alias for remote magnetId "%s" not found in URL "%s" %s'), - $remoteMagnetComment->magnetId, - $manifest->export->magnetComments, - print_r( - $remoteMagnetComment, - true - ), - ) - ); - - continue; - } - - // Skip import on magnet comment approved required - if (API_IMPORT_MAGNET_COMMENTS_APPROVED_ONLY && !$remoteMagnetComment->approved) - { - // No debug warnings in this case, continue next item - - continue; - } - - // Add new magnet comment if not exist by timestamp added for this user - if (!$db->findMagnetComment($aliasMagnetId[$remoteMagnetComment->magnetId], - $aliasUserId[$remoteMagnetComment->userId], - $remoteMagnetComment->timeAdded)) - { - // Parent comment provided - if (is_int($remoteMagnetComment->magnetCommentIdParent)) - { - $localMagnetCommentIdParent = null; // @TODO feature not in use yet - } - - else - { - $localMagnetCommentIdParent = null; - } - - $db->addMagnetComment( - $aliasMagnetId[$remoteMagnetComment->magnetId], - $aliasUserId[$remoteMagnetComment->userId], - $localMagnetCommentIdParent, - $remoteMagnetComment->value, - $remoteMagnetComment->approved, - true, - $remoteMagnetComment->timeAdded - ); - } - } - } - - // Magnet downloads - if (API_IMPORT_MAGNET_DOWNLOADS_ENABLED) - { - // Skip non-condition addresses - $error = []; - - if (!Valid::url($manifest->export->magnetDownloads, $error)) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet downloads feed URL "%s" invalid: %s'), - $manifest->export->magnetDownloads, - print_r( - $error, - true - ) - ) - ); - - continue; - } - - // Call feed - $curl = new Curl($manifest->export->magnetDownloads, API_USER_AGENT); - - $debug['http']['total']++; - - if (200 != $code = $curl->getCode()) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet downloads feed URL "%s" unreachable with code: "%s"'), - $manifest->export->magnetDownloads, - $code - ) - ); - - continue; - } - - if (!$remoteMagnetDownloads = $curl->getResponse()) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet downloads feed URL "%s" has broken response'), - $manifest->export->magnetDownloads - ) - ); - - continue; - } - - foreach ((object) $remoteMagnetDownloads as $remoteMagnetDownload) - { - // Validate - $error = []; - - if (!Valid::magnetDownload($remoteMagnetDownload, $error)) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet downloads feed URL "%s" has invalid protocol: "%s" error: "%s"'), - $manifest->export->magnetDownloads, - print_r( - $remoteMagnetDownload, - true - ), - print_r( - $error, - true - ) - ) - ); - - continue; - } - - // Aliases check - if (!isset($aliasUserId[$remoteMagnetDownload->userId])) - { - array_push( - $debug['dump'], - sprintf( - _('Local alias for remote userId "%s" not found in URL "%s" %s'), - $remoteMagnetDownload->userId, - $manifest->export->magnetDownloads, - print_r( - $remoteMagnetDownload, - true - ), - ) - ); - - continue; - } - - if (!isset($aliasMagnetId[$remoteMagnetDownload->magnetId])) - { - array_push( - $debug['dump'], - sprintf( - _('Local alias for remote magnetId "%s" not found in URL "%s" %s'), - $remoteMagnetDownload->magnetId, - $manifest->export->magnetDownloads, - print_r( - $remoteMagnetDownload, - true - ), - ) - ); - - continue; - } - - // Add new magnet download if not exist by timestamp added for this user - if (!$db->findMagnetDownload($aliasMagnetId[$remoteMagnetDownload->magnetId], - $aliasUserId[$remoteMagnetDownload->userId], - $remoteMagnetDownload->timeAdded)) - { - $db->addMagnetDownload( - $aliasMagnetId[$remoteMagnetDownload->magnetId], - $aliasUserId[$remoteMagnetDownload->userId], - $remoteMagnetDownload->timeAdded - ); - } - } - } - - // Magnet views - if (API_IMPORT_MAGNET_VIEWS_ENABLED) - { - $error = []; - - if (!Valid::url($manifest->export->magnetViews, $error)) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet views feed URL "%s" invalid: %s'), - $manifest->export->magnetViews, - print_r( - $error, - true - ) - ) - ); - - continue; - } - - // Call feed - $curl = new Curl($manifest->export->magnetViews, API_USER_AGENT); - - $debug['http']['total']++; - - if (200 != $code = $curl->getCode()) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet views feed URL "%s" unreachable with code: "%s"'), - $manifest->export->magnetViews, - $code - ) - ); - - continue; - } - - if (!$remoteMagnetViews = $curl->getResponse()) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet views feed URL "%s" has broken response'), - $manifest->export->magnetViews - ) - ); - - continue; - } - - foreach ((object) $remoteMagnetViews as $remoteMagnetView) - { - // Validate - $error = []; - - if (!Valid::magnetView($remoteMagnetView, $error)) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet views feed URL "%s" has invalid protocol: "%s" error: "%s"'), - $manifest->export->magnetViews, - print_r( - $remoteMagnetView, - true - ), - print_r( - $error, - true - ) - ) - ); - - continue; - } - - // Aliases check - if (!isset($aliasUserId[$remoteMagnetView->userId])) - { - array_push( - $debug['dump'], - sprintf( - _('Local alias for remote userId "%s" not found in URL "%s" %s'), - $remoteMagnetView->userId, - $manifest->export->magnetViews, - print_r( - $remoteMagnetView, - true - ), - ) - ); - - continue; - } - - if (!isset($aliasMagnetId[$remoteMagnetView->magnetId])) - { - array_push( - $debug['dump'], - sprintf( - _('Local alias for remote magnetId "%s" not found in URL "%s" %s'), - $remoteMagnetView->magnetId, - $manifest->export->magnetViews, - print_r( - $remoteMagnetView, - true - ), - ) - ); - - continue; - } - - // Add new magnet view if not exist by timestamp added for this user - if (!$db->findMagnetView($aliasMagnetId[$remoteMagnetView->magnetId], - $aliasUserId[$remoteMagnetView->userId], - $remoteMagnetView->timeAdded)) - { - $db->addMagnetView( - $aliasMagnetId[$remoteMagnetView->magnetId], - $aliasUserId[$remoteMagnetView->userId], - $remoteMagnetView->timeAdded - ); - } - } - } - - // Magnet stars - if (API_IMPORT_MAGNET_STARS_ENABLED) - { - $error = []; - - if (!Valid::url($manifest->export->magnetStars, $error)) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet stars feed URL "%s" invalid: %s'), - $manifest->export->magnetStars, - print_r( - $error, - true - ) - ) - ); - - continue; - } - - // Call feed - $curl = new Curl($manifest->export->magnetStars, API_USER_AGENT); - - $debug['http']['total']++; - - if (200 != $code = $curl->getCode()) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet stars feed URL "%s" unreachable with code: "%s"'), - $manifest->export->magnetStars, - $code - ) - ); - - continue; - } - - if (!$remoteMagnetStars = $curl->getResponse()) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet stars feed URL "%s" has broken response'), - $manifest->export->magnetStars - ) - ); - - continue; - } - - foreach ((object) $remoteMagnetStars as $remoteMagnetStar) - { - // Validate - $error = []; - - if (!Valid::magnetStar($remoteMagnetStar, $error)) - { - array_push( - $debug['dump'], - sprintf( - _('Magnet stars feed URL "%s" has invalid protocol: "%s" error: "%s"'), - $manifest->export->magnetStars, - print_r( - $remoteMagnetStar, - true - ), - print_r( - $error, - true - ) - ) - ); - - continue; - } - - // Aliases check - if (!isset($aliasUserId[$remoteMagnetStar->userId])) - { - array_push( - $debug['dump'], - sprintf( - _('Local alias for remote userId "%s" not found in URL "%s" %s'), - $remoteMagnetStar->userId, - $manifest->export->magnetStars, - print_r( - $remoteMagnetStar, - true - ), - ) - ); - - continue; - } - - if (!isset($aliasMagnetId[$remoteMagnetStar->magnetId])) - { - array_push( - $debug['dump'], - sprintf( - _('Local alias for remote magnetId "%s" not found in URL "%s" %s'), - $remoteMagnetStar->magnetId, - $manifest->export->magnetStars, - print_r( - $remoteMagnetStar, - true - ), - ) - ); - - continue; - } - - // Add new magnet star if not exist by timestamp added for this user - if (!$db->findMagnetStar($aliasMagnetId[$remoteMagnetStar->magnetId], - $aliasUserId[$remoteMagnetStar->userId], - $remoteMagnetStar->timeAdded)) - { - $db->addMagnetStar( - $aliasMagnetId[$remoteMagnetStar->magnetId], - $aliasUserId[$remoteMagnetStar->userId], - $remoteMagnetStar->value, - $remoteMagnetStar->timeAdded - ); - } - } - } - } - } - } - - $db->commit(); - -} catch (EXception $e) { - - $db->rollBack(); - - var_dump($e); -} - -// Debug output -$debug['time']['total'] = microtime(true) - $debug['time']['total']; - -$debug['memory']['total'] = memory_get_usage() - $debug['memory']['start']; -$debug['memory']['peaks'] = memory_get_peak_usage(); - -$debug['db']['total']['select'] = $db->getDebug()->query->select->total; -$debug['db']['total']['insert'] = $db->getDebug()->query->insert->total; -$debug['db']['total']['update'] = $db->getDebug()->query->update->total; -$debug['db']['total']['delete'] = $db->getDebug()->query->delete->total; - -print_r($debug); - -// Debug log -if (LOG_CRONTAB_IMPORT_FEED_ENABLED) -{ - @mkdir(LOG_DIRECTORY, 0770, true); - - if ($handle = fopen(LOG_DIRECTORY . '/' . LOG_CRONTAB_IMPORT_FEED_FILENAME, 'a+')) - { - fwrite($handle, print_r($debug, true)); - fclose($handle); - - chmod(LOG_DIRECTORY . '/' . LOG_CRONTAB_IMPORT_FEED_FILENAME, 0770); - } -} \ No newline at end of file diff --git a/src/crontab/scrape.php b/src/crontab/scrape.php deleted file mode 100644 index f974165..0000000 --- a/src/crontab/scrape.php +++ /dev/null @@ -1,158 +0,0 @@ - [ - 'ISO8601' => date('c'), - 'total' => microtime(true), - ], - 'http' => - [ - 'total' => 0, - ], - 'memory' => - [ - 'start' => memory_get_usage(), - 'total' => 0, - 'peaks' => 0 - ], -]; - -// Init Scraper -try { - - $scraper = new Scrapeer\Scraper(); - -} catch(Exception $e) { - - var_dump($e); - - exit; -} - -// Begin -try { - - $db->beginTransaction(); - - // Reset time offline by timeout - $db->resetMagnetToAddressTrackerTimeOfflineByTimeout( - CRAWLER_SCRAPE_TIME_OFFLINE_TIMEOUT - ); - - foreach ($db->getMagnetToAddressTrackerScrapeQueue(CRAWLER_SCRAPE_QUEUE_LIMIT) as $queue) - { - $hashes = []; - foreach ($db->findMagnetToInfoHashByMagnetId($queue->magnetId) as $result) - { - $hashes[] = $db->getInfoHash($result->infoHashId)->value; - } - - if ($addressTracker = $db->getAddressTracker($queue->addressTrackerId)) - { - // Build url - $scheme = $db->getScheme($addressTracker->schemeId); - $host = $db->getHost($addressTracker->hostId); - $port = $db->getPort($addressTracker->portId); - $uri = $db->getUri($addressTracker->uriId); - - $url = $port->value ? sprintf('%s://%s:%s%s', $scheme->value, - $host->value, - $port->value, - $uri->value) : sprintf('%s://%s%s', $scheme->value, - $host->value, - $uri->value); - - foreach ($hashes as $hash) - { - if ($scrape = $scraper->scrape([$hash], [$url], null, 1)) - { - $db->updateMagnetToAddressTrackerTimeOffline( - $queue->magnetToAddressTrackerId, - null - ); - - if (isset($scrape[$hash]['seeders'])) - { - $db->updateMagnetToAddressTrackerSeeders( - $queue->magnetToAddressTrackerId, - (int) $scrape[$hash]['seeders'], - time() - ); - } - - if (isset($scrape[$hash]['completed'])) - { - $db->updateMagnetToAddressTrackerCompleted( - $queue->magnetToAddressTrackerId, - (int) $scrape[$hash]['completed'], - time() - ); - } - - if (isset($scrape[$hash]['leechers'])) - { - $db->updateMagnetToAddressTrackerLeechers( - $queue->magnetToAddressTrackerId, - (int) $scrape[$hash]['leechers'], - time() - ); - } - } - else - { - $db->updateMagnetToAddressTrackerTimeOffline( - $queue->magnetToAddressTrackerId, - time() - ); - } - } - } - } - - $db->commit(); - -} catch (EXception $e) { - - $db->rollback(); - - var_dump($e); -} - -// Debug output -$debug['time']['total'] = microtime(true) - $debug['time']['total']; - -$debug['memory']['total'] = memory_get_usage() - $debug['memory']['start']; -$debug['memory']['peaks'] = memory_get_peak_usage(); - -$debug['db']['total']['select'] = $db->getDebug()->query->select->total; -$debug['db']['total']['insert'] = $db->getDebug()->query->insert->total; -$debug['db']['total']['update'] = $db->getDebug()->query->update->total; -$debug['db']['total']['delete'] = $db->getDebug()->query->delete->total; - -print_r($debug); - -// Debug log -if (LOG_CRONTAB_SCRAPE_ENABLED) -{ - @mkdir(LOG_DIRECTORY, 0774, true); - - if ($handle = fopen(LOG_DIRECTORY . '/' . LOG_CRONTAB_SCRAPE_FILENAME, 'a+')) - { - fwrite($handle, print_r($debug, true)); - fclose($handle); - - chmod(LOG_DIRECTORY . '/' . LOG_CRONTAB_SCRAPE_FILENAME, 0774); - } -} \ No newline at end of file diff --git a/src/crontab/sitemap.php b/src/crontab/sitemap.php deleted file mode 100644 index 1c65e87..0000000 --- a/src/crontab/sitemap.php +++ /dev/null @@ -1,86 +0,0 @@ - [ - 'ISO8601' => date('c'), - 'total' => microtime(true), - ], - 'http' => - [ - 'total' => 0, - ], - 'memory' => - [ - 'start' => memory_get_usage(), - 'total' => 0, - 'peaks' => 0 - ], -]; - -// Begin -try { - - // Delete cache - @unlink(__DIR__ . '/../public/sitemap.xml'); - - if ($handle = fopen(__DIR__ . '/../public/sitemap.xml', 'w+')) - { - - fwrite($handle, ''); - fwrite($handle, ''); - - foreach ($db->getMagnets() as $magnet) - { - if ($magnet->public && $magnet->approved) - { - fwrite($handle, sprintf('%s/magnet.php?magnetId=%s', WEBSITE_URL, $magnet->magnetId)); - } - } - - fwrite($handle, ''); - fclose($handle); - } - -} catch (EXception $e) { - - var_dump($e); -} - -// Debug output -$debug['time']['total'] = microtime(true) - $debug['time']['total']; - -$debug['memory']['total'] = memory_get_usage() - $debug['memory']['start']; -$debug['memory']['peaks'] = memory_get_peak_usage(); - -$debug['db']['total']['select'] = $db->getDebug()->query->select->total; -$debug['db']['total']['insert'] = $db->getDebug()->query->insert->total; -$debug['db']['total']['update'] = $db->getDebug()->query->update->total; -$debug['db']['total']['delete'] = $db->getDebug()->query->delete->total; - -print_r($debug); - -// Debug log -if (LOG_CRONTAB_SITEMAP_ENABLED) -{ - @mkdir(LOG_DIRECTORY, 0774, true); - - if ($handle = fopen(LOG_DIRECTORY . '/' . LOG_CRONTAB_SITEMAP_FILENAME, 'a+')) - { - fwrite($handle, print_r($debug, true)); - fclose($handle); - - chmod(LOG_DIRECTORY . '/' . LOG_CRONTAB_SITEMAP_FILENAME, 0774); - } -} \ No newline at end of file diff --git a/src/library/curl.php b/src/library/curl.php deleted file mode 100644 index 24c4021..0000000 --- a/src/library/curl.php +++ /dev/null @@ -1,97 +0,0 @@ -_connection = curl_init($url); - - if ($userAgent) - { - curl_setopt($this->_connection, CURLOPT_USERAGENT, $userAgent); - } - - if (!empty($post)) - { - curl_setopt($this->_connection, CURLOPT_POST, true); - curl_setopt($this->_connection, CURLOPT_POSTFIELDS, http_build_query($post)); - } - - if ($header) { - curl_setopt($this->_connection, CURLOPT_HEADER, true); - } - - if ($followLocation) { - curl_setopt($this->_connection, CURLOPT_FOLLOWLOCATION, true); - curl_setopt($this->_connection, CURLOPT_MAXREDIRS, $maxRedirects); - } - - curl_setopt($this->_connection, CURLOPT_FRESH_CONNECT, true); - curl_setopt($this->_connection, CURLOPT_RETURNTRANSFER, true); - curl_setopt($this->_connection, CURLOPT_CONNECTTIMEOUT, $connectTimeout); - curl_setopt($this->_connection, CURLOPT_TIMEOUT, $connectTimeout); - curl_setopt($this->_connection, CURLOPT_SSL_VERIFYHOST, $sslVerifyHost); - curl_setopt($this->_connection, CURLOPT_SSL_VERIFYPEER, $sslVerifyPeer); - - $this->_response = curl_exec($this->_connection); - } - - public function __destruct() - { - curl_close($this->_connection); - } - - public function getError() - { - if (curl_errno($this->_connection)) - { - return curl_errno($this->_connection); - } - - else - { - return false; - } - } - - public function getCode() - { - return curl_getinfo($this->_connection, CURLINFO_HTTP_CODE); - } - - public function getContentType() - { - return curl_getinfo($this->_connection, CURLINFO_CONTENT_TYPE); - } - - public function getSizeDownload() - { - return curl_getinfo($this->_connection, CURLINFO_SIZE_DOWNLOAD); - } - - public function getSizeRequest() - { - return curl_getinfo($this->_connection, CURLINFO_REQUEST_SIZE); - } - - public function getTotalTime() - { - return curl_getinfo($this->_connection, CURLINFO_TOTAL_TIME_T); - } - - public function getResponse(bool $json = true) - { - return $json ? json_decode($this->_response) : $this->_response; - } -} \ No newline at end of file diff --git a/src/library/environment.php b/src/library/environment.php deleted file mode 100644 index b85516d..0000000 --- a/src/library/environment.php +++ /dev/null @@ -1,27 +0,0 @@ -1) or string of infohash(es). - * @param array|string $trackers List (>1) or string of tracker(s). - * @param int|null $max_trackers Optional. Maximum number of trackers to be scraped, Default all. - * @param int $timeout Optional. Maximum time for each tracker scrape in seconds, Default 2. - * @param bool $announce Optional. Use announce instead of scrape, Default false. - * @return array List of results. - */ - public function scrape( $hashes, $trackers, $max_trackers = null, $timeout = 2, $announce = false ) { - $final_result = array(); - - if ( empty( $trackers ) ) { - $this->errors[] = 'No tracker specified, aborting.'; - return $final_result; - } else if ( ! is_array( $trackers ) ) { - $trackers = array( $trackers ); - } - - if ( is_int( $timeout ) ) { - $this->timeout = $timeout; - } else { - $this->timeout = 2; - $this->errors[] = 'Timeout must be an integer. Using default value.'; - } - - try { - $this->infohashes = $this->normalize_infohashes( $hashes ); - } catch ( \RangeException $e ) { - $this->errors[] = $e->getMessage(); - return $final_result; - } - - $max_iterations = is_int( $max_trackers ) ? $max_trackers : count( $trackers ); - foreach ( $trackers as $index => $tracker ) { - if ( ! empty( $this->infohashes ) && $index < $max_iterations ) { - $info = parse_url( $tracker ); - $protocol = $info['scheme']; - $host = $info['host']; - if ( empty( $protocol ) || empty( $host ) ) { - $this->errors[] = 'Skipping invalid tracker (' . $tracker . ').'; - continue; - } - - $port = isset( $info['port'] ) ? $info['port'] : null; - $path = isset( $info['path'] ) ? $info['path'] : null; - $passkey = $this->get_passkey( $path ); - $result = $this->try_scrape( $protocol, $host, $port, $passkey, $announce ); - $final_result = array_merge( $final_result, $result ); - continue; - } - break; - } - return $final_result; - } - - /** - * Normalizes the given hashes - * - * @throws \RangeException If amount of valid infohashes > 64 or < 1. - * - * @param array $infohashes List of infohash(es). - * @return array Normalized infohash(es). - */ - private function normalize_infohashes( $infohashes ) { - if ( ! is_array( $infohashes ) ) { - $infohashes = array( $infohashes ); - } - - foreach ( $infohashes as $index => $infohash ) { - if ( ! preg_match( '/^[a-f0-9]{40}$/i', $infohash ) ) { - $this->errors[] = 'Invalid infohash skipped (' . $infohash . ').'; - unset( $infohashes[ $index ] ); - } - } - - $total_infohashes = count( $infohashes ); - if ( $total_infohashes > 64 || $total_infohashes < 1 ) { - throw new \RangeException( 'Invalid amount of valid infohashes (' . $total_infohashes . ').' ); - } - - $infohashes = array_values( $infohashes ); - - return $infohashes; - } - - /** - * Returns the passkey found in the scrape request. - * - * @param string $path Path from the scrape request. - * @return string Passkey or empty string. - */ - private function get_passkey( $path ) { - if ( ! is_null( $path ) && preg_match( '/[a-z0-9]{32}/i', $path, $matches ) ) { - return '/' . $matches[0]; - } - - return ''; - } - - /** - * Tries to scrape with a single tracker. - * - * @throws \Exception In case of unsupported protocol. - * - * @param string $protocol Protocol of the tracker. - * @param string $host Domain or address of the tracker. - * @param int $port Optional. Port number of the tracker. - * @param string $passkey Optional. Passkey provided in the scrape request. - * @param bool $announce Optional. Use announce instead of scrape, Default false. - * @return array List of results. - */ - private function try_scrape( $protocol, $host, $port, $passkey, $announce ) { - $infohashes = $this->infohashes; - $this->infohashes = array(); - $results = array(); - try { - switch ( $protocol ) { - case 'udp': - $port = isset( $port ) ? $port : 80; - $results = $this->scrape_udp( $infohashes, $host, $port, $announce ); - break; - case 'http': - $port = isset( $port ) ? $port : 80; - $results = $this->scrape_http( $infohashes, $protocol, $host, $port, $passkey, $announce ); - break; - case 'https': - $port = isset( $port ) ? $port : 443; - $results = $this->scrape_http( $infohashes, $protocol, $host, $port, $passkey, $announce ); - break; - default: - throw new \Exception( 'Unsupported protocol (' . $protocol . '://' . $host . ').' ); - } - } catch ( \Exception $e ) { - $this->infohashes = $infohashes; - $this->errors[] = $e->getMessage(); - } - return $results; - } - - /** - * Initiates the HTTP(S) scraping - * - * @param array|string $infohashes List (>1) or string of infohash(es). - * @param string $protocol Protocol to use for the scraping. - * @param string $host Domain or IP address of the tracker. - * @param int $port Optional. Port number of the tracker, Default 80 (HTTP) or 443 (HTTPS). - * @param string $passkey Optional. Passkey provided in the scrape request. - * @param bool $announce Optional. Use announce instead of scrape, Default false. - * @return array List of results. - */ - private function scrape_http( $infohashes, $protocol, $host, $port, $passkey, $announce ) { - if ( true === $announce ) { - $response = $this->http_announce( $infohashes, $protocol, $host, $port, $passkey ); - } else { - $query = $this->http_query( $infohashes, $protocol, $host, $port, $passkey ); - $response = $this->http_request( $query, $host, $port ); - } - $results = $this->http_data( $response, $infohashes, $host ); - - return $results; - } - - /** - * Builds the HTTP(S) query - * - * @param array|string $infohashes List (>1) or string of infohash(es). - * @param string $protocol Protocol to use for the scraping. - * @param string $host Domain or IP address of the tracker. - * @param int $port Port number of the tracker, Default 80 (HTTP) or 443 (HTTPS). - * @param string $passkey Optional. Passkey provided in the scrape request. - * @return string Request query. - */ - private function http_query( $infohashes, $protocol, $host, $port, $passkey ) { - $tracker_url = $protocol . '://' . $host . ':' . $port . $passkey; - $scrape_query = ''; - - foreach ( $infohashes as $index => $infohash ) { - if ( $index > 0 ) { - $scrape_query .= '&info_hash=' . urlencode( pack( 'H*', $infohash ) ); - } else { - $scrape_query .= '/scrape?info_hash=' . urlencode( pack( 'H*', $infohash ) ); - } - } - $request_query = $tracker_url . $scrape_query; - - return $request_query; - } - - /** - * Executes the query and returns the result - * - * @throws \Exception If the connection can't be established. - * @throws \Exception If the response isn't valid. - * - * @param string $query The query that will be executed. - * @param string $host Domain or IP address of the tracker. - * @param int $port Port number of the tracker, Default 80 (HTTP) or 443 (HTTPS). - * @return string Request response. - */ - private function http_request( $query, $host, $port ) { - $context = stream_context_create( array( - 'http' => array( - 'timeout' => $this->timeout, - ), - )); - - if ( false === ( $response = @file_get_contents( $query, false, $context ) ) ) { - throw new \Exception( 'Invalid scrape connection (' . $host . ':' . $port . ').' ); - } - - if ( substr( $response, 0, 12 ) !== 'd5:filesd20:' ) { - throw new \Exception( 'Invalid scrape response (' . $host . ':' . $port . ').' ); - } - - return $response; - } - - /** - * Builds the query, sends the announce request and returns the data - * - * @throws \Exception If the connection can't be established. - * - * @param array|string $infohashes List (>1) or string of infohash(es). - * @param string $protocol Protocol to use for the scraping. - * @param string $host Domain or IP address of the tracker. - * @param int $port Port number of the tracker, Default 80 (HTTP) or 443 (HTTPS). - * @param string $passkey Optional. Passkey provided in the scrape request. - * @return string Request response. - */ - private function http_announce( $infohashes, $protocol, $host, $port, $passkey ) { - $tracker_url = $protocol . '://' . $host . ':' . $port . $passkey; - $context = stream_context_create( array( - 'http' => array( - 'timeout' => $this->timeout, - ), - )); - - $response_data = ''; - foreach ( $infohashes as $infohash ) { - $query = $tracker_url . '/announce?info_hash=' . urlencode( pack( 'H*', $infohash ) ); - if ( false === ( $response = @file_get_contents( $query, false, $context ) ) ) { - throw new \Exception( 'Invalid announce connection (' . $host . ':' . $port . ').' ); - } - - if ( substr( $response, 0, 12 ) !== 'd8:completei' || - substr( $response, 0, 46 ) === 'd8:completei0e10:downloadedi0e10:incompletei1e' ) { - continue; - } - - $ben_hash = '20:' . pack( 'H*', $infohash ) . 'd'; - $response_data .= $ben_hash . $response; - } - - return $response_data; - } - - /** - * Parses the response and returns the data - * - * @param string $response The response that will be parsed. - * @param array $infohashes List of infohash(es). - * @param string $host Domain or IP address of the tracker. - * @return array Parsed data. - */ - private function http_data( $response, $infohashes, $host ) { - $torrents_data = array(); - - foreach ( $infohashes as $infohash ) { - $ben_hash = '20:' . pack( 'H*', $infohash ) . 'd'; - $start_pos = strpos( $response, $ben_hash ); - if ( false !== $start_pos ) { - $start = $start_pos + 24; - $head = substr( $response, $start ); - $end = strpos( $head, 'ee' ) + 1; - $data = substr( $response, $start, $end ); - - $seeders = '8:completei'; - $torrent_info['seeders'] = $this->get_information( $data, $seeders, 'e' ); - - $completed = '10:downloadedi'; - $torrent_info['completed'] = $this->get_information( $data, $completed, 'e' ); - - $leechers = '10:incompletei'; - $torrent_info['leechers'] = $this->get_information( $data, $leechers, 'e' ); - - $torrents_data[ $infohash ] = $torrent_info; - } else { - $this->collect_infohash( $infohash ); - $this->errors[] = 'Invalid infohash (' . $infohash . ') for tracker: ' . $host . '.'; - } - } - - return $torrents_data; - } - - /** - * Parses a string and returns the data between $start and $end. - * - * @param string $data The data that will be parsed. - * @param string $start Beginning part of the data. - * @param string $end Ending part of the data. - * @return int Parsed information or 0. - */ - private function get_information( $data, $start, $end ) { - $start_pos = strpos( $data, $start ); - if ( false !== $start_pos ) { - $start = $start_pos + strlen( $start ); - $head = substr( $data, $start ); - $end = strpos( $head, $end ); - $information = substr( $data, $start, $end ); - - return (int) $information; - } - - return 0; - } - - /** - * Initiates the UDP scraping - * - * @param array|string $infohashes List (>1) or string of infohash(es). - * @param string $host Domain or IP address of the tracker. - * @param int $port Optional. Port number of the tracker, Default 80. - * @param bool $announce Optional. Use announce instead of scrape, Default false. - * @return array List of results. - */ - private function scrape_udp( $infohashes, $host, $port, $announce ) { - list( $socket, $transaction_id, $connection_id ) = $this->prepare_udp( $host, $port ); - - if ( true === $announce ) { - $response = $this->udp_announce( $socket, $infohashes, $connection_id ); - $keys = 'Nleechers/Nseeders'; - $start = 12; - $end = 16; - $offset = 20; - } else { - $response = $this->udp_scrape( $socket, $infohashes, $connection_id, $transaction_id, $host, $port ); - $keys = 'Nseeders/Ncompleted/Nleechers'; - $start = 8; - $end = $offset = 12; - } - $results = $this->udp_scrape_data( $response, $infohashes, $host, $keys, $start, $end, $offset ); - - return $results; - } - - /** - * Prepares the UDP connection - * - * @param string $host Domain or IP address of the tracker. - * @param int $port Optional. Port number of the tracker, Default 80. - * @return array Created socket, transaction ID and connection ID. - */ - private function prepare_udp( $host, $port ) { - $socket = $this->udp_create_connection( $host, $port ); - $transaction_id = $this->udp_connection_request( $socket ); - $connection_id = $this->udp_connection_response( $socket, $transaction_id, $host, $port ); - - return array( $socket, $transaction_id, $connection_id ); - } - - /** - * Creates the UDP socket and establishes the connection - * - * @throws \Exception If the socket couldn't be created or connected to. - * - * @param string $host Domain or IP address of the tracker. - * @param int $port Port number of the tracker, Default 80. - * @return resource $socket Created and connected socket. - */ - private function udp_create_connection( $host, $port ) { - if ( false === ( $socket = @socket_create( AF_INET, SOCK_DGRAM, SOL_UDP ) ) ) { - throw new \Exception( "Couldn't create socket." ); - } - - $timeout = $this->timeout; - socket_set_option( $socket, SOL_SOCKET, SO_RCVTIMEO, array( 'sec' => $timeout, 'usec' => 0 ) ); - socket_set_option( $socket, SOL_SOCKET, SO_SNDTIMEO, array( 'sec' => $timeout, 'usec' => 0 ) ); - if ( false === @socket_connect( $socket, $host, $port ) ) { - throw new \Exception( "Couldn't connect to socket." ); - } - - return $socket; - } - - /** - * Writes to the connected socket and returns the transaction ID - * - * @throws \Exception If the socket couldn't be written to. - * - * @param resource $socket The socket resource. - * @return int The transaction ID. - */ - private function udp_connection_request( $socket ) { - $connection_id = "\x00\x00\x04\x17\x27\x10\x19\x80"; - $action = pack( 'N', 0 ); - $transaction_id = mt_rand( 0, 2147483647 ); - $buffer = $connection_id . $action . pack( 'N', $transaction_id ); - if ( false === @socket_write( $socket, $buffer, strlen( $buffer ) ) ) { - socket_close( $socket ); - throw new \Exception( "Couldn't write to socket." ); - } - - return $transaction_id; - } - - /** - * Reads the connection response and returns the connection ID - * - * @throws \Exception If anything fails with the scraping. - * - * @param resource $socket The socket resource. - * @param int $transaction_id The transaction ID. - * @param string $host Domain or IP address of the tracker. - * @param int $port Port number of the tracker, Default 80. - * @return string The connection ID. - */ - private function udp_connection_response( $socket, $transaction_id, $host, $port ) { - if ( false === ( $response = @socket_read( $socket, 16 ) ) ) { - socket_close( $socket ); - throw new \Exception( 'Invalid scrape connection! (' . $host . ':' . $port . ').' ); - } - - if ( strlen( $response ) < 16 ) { - socket_close( $socket ); - throw new \Exception( 'Invalid scrape response (' . $host . ':' . $port . ').' ); - } - - $result = unpack( 'Naction/Ntransaction_id', $response ); - if ( 0 !== $result['action'] || $result['transaction_id'] !== $transaction_id ) { - socket_close( $socket ); - throw new \Exception( 'Invalid scrape result (' . $host . ':' . $port . ').' ); - } - - $connection_id = substr( $response, 8, 8 ); - - return $connection_id; - } - - /** - * Reads the socket response and returns the torrent data - * - * @throws \Exception If anything fails while reading the response. - * - * @param resource $socket The socket resource. - * @param array $hashes List (>1) or string of infohash(es). - * @param string $connection_id The connection ID. - * @param int $transaction_id The transaction ID. - * @param string $host Domain or IP address of the tracker. - * @param int $port Port number of the tracker, Default 80. - * @return string Response data. - */ - private function udp_scrape( $socket, $hashes, $connection_id, $transaction_id, $host, $port ) { - $this->udp_scrape_request( $socket, $hashes, $connection_id, $transaction_id ); - - $read_length = 8 + ( 12 * count( $hashes ) ); - if ( false === ( $response = @socket_read( $socket, $read_length ) ) ) { - socket_close( $socket ); - throw new \Exception( 'Invalid scrape connection (' . $host . ':' . $port . ').' ); - } - socket_close( $socket ); - - if ( strlen( $response ) < $read_length ) { - throw new \Exception( 'Invalid scrape response (' . $host . ':' . $port . ').' ); - } - - $result = unpack( 'Naction/Ntransaction_id', $response ); - if ( 2 !== $result['action'] || $result['transaction_id'] !== $transaction_id ) { - throw new \Exception( 'Invalid scrape result (' . $host . ':' . $port . ').' ); - } - - return $response; - } - - /** - * Writes to the connected socket - * - * @throws \Exception If the socket couldn't be written to. - * - * @param resource $socket The socket resource. - * @param array $hashes List (>1) or string of infohash(es). - * @param string $connection_id The connection ID. - * @param int $transaction_id The transaction ID. - */ - private function udp_scrape_request( $socket, $hashes, $connection_id, $transaction_id ) { - $action = pack( 'N', 2 ); - - $infohashes = ''; - foreach ( $hashes as $infohash ) { - $infohashes .= pack( 'H*', $infohash ); - } - - $buffer = $connection_id . $action . pack( 'N', $transaction_id ) . $infohashes; - if ( false === @socket_write( $socket, $buffer, strlen( $buffer ) ) ) { - socket_close( $socket ); - throw new \Exception( "Couldn't write to socket." ); - } - } - - /** - * Writes the announce to the connected socket - * - * @throws \Exception If the socket couldn't be written to. - * - * @param resource $socket The socket resource. - * @param array $hashes List (>1) or string of infohash(es). - * @param string $connection_id The connection ID. - * @return string Torrent(s) data. - */ - private function udp_announce( $socket, $hashes, $connection_id ) { - $action = pack( 'N', 1 ); - $downloaded = $left = $uploaded = "\x30\x30\x30\x30\x30\x30\x30\x30"; - $peer_id = $this->random_peer_id(); - $event = pack( 'N', 3 ); - $ip_addr = pack( 'N', 0 ); - $key = pack( 'N', mt_rand( 0, 2147483647 ) ); - $num_want = -1; - $ann_port = pack( 'N', mt_rand( 0, 255 ) ); - - $response_data = ''; - foreach ( $hashes as $infohash ) { - $transaction_id = mt_rand( 0, 2147483647 ); - $buffer = $connection_id . $action . pack( 'N', $transaction_id ) . pack( 'H*', $infohash ) . - $peer_id . $downloaded . $left . $uploaded . $event . $ip_addr . $key . $num_want . $ann_port; - - if ( false === @socket_write( $socket, $buffer, strlen( $buffer ) ) ) { - socket_close( $socket ); - throw new \Exception( "Couldn't write announce to socket." ); - } - - $response = $this->udp_verify_announce( $socket, $transaction_id ); - if ( false === $response ) { - continue; - } - - $response_data .= $response; - } - socket_close( $socket ); - - return $response_data; - } - - /** - * Generates a random peer ID - * - * @return string Generated peer ID. - */ - private function random_peer_id() { - $identifier = '-SP0054-'; - $chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; - $peer_id = $identifier . substr( str_shuffle( $chars ), 0, 12 ); - - return $peer_id; - } - - /** - * Verifies the correctness of the announce response - * - * @param resource $socket The socket resource. - * @param int $transaction_id The transaction ID. - * @return string Response data. - */ - private function udp_verify_announce( $socket, $transaction_id ) { - if ( false === ( $response = @socket_read( $socket, 20 ) ) ) { - return false; - } - - if ( strlen( $response ) < 20 ) { - return false; - } - - $result = unpack( 'Naction/Ntransaction_id', $response ); - if ( 1 !== $result['action'] || $result['transaction_id'] !== $transaction_id ) { - return false; - } - - return $response; - } - - /** - * Reads the socket response and returns the torrent data - * - * @param string $response Data from the request response. - * @param array $hashes List (>1) or string of infohash(es). - * @param string $host Domain or IP address of the tracker. - * @param string $keys Keys for the unpacked information. - * @param int $start Start of the content we want to unpack. - * @param int $end End of the content we want to unpack. - * @param int $offset Offset to the next content part. - * @return array Scraped torrent data. - */ - private function udp_scrape_data( $response, $hashes, $host, $keys, $start, $end, $offset ) { - $torrents_data = array(); - - foreach ( $hashes as $infohash ) { - $byte_string = substr( $response, $start, $end ); - $data = unpack( 'N', $byte_string ); - $content = $data[1]; - if ( ! empty( $content ) ) { - $results = unpack( $keys, $byte_string ); - $torrents_data[ $infohash ] = $results; - } else { - $this->collect_infohash( $infohash ); - $this->errors[] = 'Invalid infohash (' . $infohash . ') for tracker: ' . $host . '.'; - } - $start += $offset; - } - - return $torrents_data; - } - - /** - * Collects info-hashes that couldn't be scraped. - * - * @param string $infohash Infohash that wasn't scraped. - */ - private function collect_infohash( $infohash ) { - $this->infohashes[] = $infohash; - } - - /** - * Checks if there are any errors - * - * @return bool True or false, depending if errors are present or not. - */ - public function has_errors() { - return ! empty( $this->errors ); - } - - /** - * Returns all the errors that were logged - * - * @return array All the logged errors. - */ - public function get_errors() { - return $this->errors; - } -} diff --git a/src/library/time.php b/src/library/time.php deleted file mode 100644 index 9199d3c..0000000 --- a/src/library/time.php +++ /dev/null @@ -1,45 +0,0 @@ - _('year'), - 30 * 24 * 60 * 60 => _('month'), - 24 * 60 * 60 => _('day'), - 60 * 60 => _('hour'), - 60 => _('minute'), - 1 => _('second') - ]; - - $plural = [ - _('year') => _('years'), - _('month') => _('months'), - _('day') => _('days'), - _('hour') => _('hours'), - _('minute') => _('minutes'), - _('second') => _('seconds') - ]; - - foreach ($values as $key => $value) - { - $result = $diff / $key; - - if ($result >= 1) - { - $round = round($result); - - return sprintf('%s %s ago', $round, $round > 1 ? $plural[$value] : $value); - } - } - } -} diff --git a/src/public/api/push.php b/src/public/api/push.php deleted file mode 100644 index ad63354..0000000 --- a/src/public/api/push.php +++ /dev/null @@ -1,938 +0,0 @@ - [ - 'ISO8601' => date('c'), - 'total' => microtime(true), - ], - 'memory' => - [ - 'start' => memory_get_usage(), - 'total' => 0, - 'peaks' => 0 - ], - 'exception' => [] -]; - -// Define response -$response = -[ - 'status' => false, - 'message' => _('Internal server error'), - 'data' => [ - 'user' => [], - 'magnet' => [], - 'magnetDownload' => [], - 'magnetComment' => [], - 'magnetView' => [], - 'magnetStar' => [], - ] -]; - -// Init connections whitelist -$connectionWhiteList = []; - -foreach (json_decode(file_get_contents(__DIR__ . '/../../config/nodes.json')) as $node) -{ - // Skip non-condition addresses - if (!Valid::url($node->manifest)) - { - continue; - } - - // Skip current host - $thisUrl = Yggverse\Parser\Url::parse(WEBSITE_URL); - $manifestUrl = Yggverse\Parser\Url::parse($node->manifest); - - if (empty($thisUrl->host->name) || - empty($manifestUrl->host->name) || - $manifestUrl->host->name == $thisUrl->host->name) // @TODO some mirrors could be available on same host sub-folders, improve condition - { - continue; - } - - $connectionWhiteList[] = str_replace(['[',']'], false, $manifestUrl->host->name); -} - -// API import enabled -$error = []; - -if (!API_IMPORT_ENABLED) -{ - $response = - [ - 'status' => false, - 'message' => _('Import API disabled') - ]; -} - -// Push API import enabled -else if (!API_IMPORT_PUSH_ENABLED) -{ - $response = - [ - 'status' => false, - 'message' => _('Push API import disabled') - ]; -} - -// Yggdrasil connections only -else if (!Valid::host($_SERVER['REMOTE_ADDR'], $error)) -{ - $response = - [ - 'status' => false, - 'message' => $error - ]; -} - -// Init session -else if (!in_array($_SERVER['REMOTE_ADDR'], $connectionWhiteList)) -{ - $response = - [ - 'status' => false, - 'message' => sprintf( - _('Push API access denied for host "%s"'), - $_SERVER['REMOTE_ADDR'] - ) - ]; -} - -// Init session -else if (!$userId = $db->initUserId($_SERVER['REMOTE_ADDR'], USER_DEFAULT_APPROVED, time())) -{ - $response = - [ - 'status' => false, - 'message' => _('Could not init user session for this connection') - ]; -} - -// Validate required fields -else if (empty($_POST['data'])) -{ - $response = - [ - 'status' => false, - 'message' => _('Request protocol invalid') - ]; -} - -// Validate required fields -else if (false === $data = json_decode($_POST['data'])) -{ - $response = - [ - 'status' => false, - 'message' => _('Could not decode data requested') - ]; -} - -// Import begin -else -{ - $response = - [ - 'status' => true, - 'message' => sprintf( - _('Connection for "%s" established'), - $_SERVER['REMOTE_ADDR'] - ) - ]; - - // Init alias registry - $aliasUserId = []; - $aliasMagnetId = []; - - try { - - // Transaction begin - $db->beginTransaction(); - - // Process request - foreach ((object) $data as $field => $remote) - { - // Process alias fields - switch ($field) - { - case 'user': - - if (!API_IMPORT_USERS_ENABLED) - { - $response['user'][] = [ - 'status' => false, - 'message' => _('Users import disabled on this node. Related content skipped.') - ]; - - continue 2; - } - - // Validate remote fields - $error = []; - - if (!Valid::user($remote, $error)) - { - $response['user'][] = [ - 'status' => false, - 'message' => sprintf( - _('User data mismatch protocol with error: %s'), - print_r($error, true) - ), - ]; - - continue 2; - } - - // Skip import on user approved required - if (API_IMPORT_USERS_APPROVED_ONLY && !$remote->approved) - { - $response['user'][] = [ - 'status' => false, - 'message' => _('Node accepting approved users only') - ]; - - continue 2; - } - - // Init local user by remote address - if (!$local = $db->getUser($db->initUserId($remote->address, - USER_AUTO_APPROVE_ON_IMPORT_APPROVED ? $remote->approved : USER_DEFAULT_APPROVED, - $remote->timeAdded))) - { - $response['user'][] = [ - 'status' => false, - 'message' => _('Could not init user profile') - ]; - - continue 2; - } - - else - { - $response['user'][] = [ - 'status' => true, - 'message' => sprintf( - _('User profile successfully associated with ID "%s"'), - $local->userId - ) - ]; - } - - // Register user alias - $aliasUserId[$remote->userId] = $local->userId; - - // Update time added if newer - if ($local->timeAdded < $remote->timeAdded) - { - $db->updateUserTimeAdded( - $local->userId, - $remote->timeAdded - ); - - $response['user'][] = [ - 'status' => true, - 'message' => sprintf( - _('Field "timeAdded" changed to newer value for user ID "%s"'), - $local->userId - ) - ]; - } - - // Update user info if newer - if ($local->timeUpdated < $remote->timeUpdated) - { - // Update time updated - $db->updateUserTimeUpdated( - $local->userId, - $remote->timeUpdated - ); - - $response['user'][] = [ - 'status' => true, - 'message' => sprintf( - _('Field "timeUpdated" changed to newer value for user ID "%s"'), - $local->userId - ) - ]; - - // Update approved for existing user - if (USER_AUTO_APPROVE_ON_IMPORT_APPROVED && $local->approved !== $remote->approved && $remote->approved) - { - $db->updateUserApproved( - $local->userId, - $remote->approved, - $remote->timeUpdated - ); - - $response['user'][] = [ - 'status' => true, - 'message' => sprintf( - _('Field "approved" changed to newer value for user ID "%s"'), - $local->userId - ) - ]; - } - - // Set public as received remotely - if (!$local->public) - { - $db->updateUserPublic( - $local->userId, - true, - $remote->timeUpdated - ); - - $response['user'][] = [ - 'status' => true, - 'message' => sprintf( - _('Field "public" changed to newer value for user ID "%s"'), - $local->userId - ) - ]; - } - } - - break; - case 'magnet': - - if (!API_IMPORT_MAGNETS_ENABLED) - { - $response['magnet'][] = [ - 'status' => false, - 'message' => _('Magnets import disabled on this node. Related content skipped.') - ]; - - continue 2; - } - - // Validate remote fields - $error = []; - - if (!Valid::magnet($remote, $error)) - { - $response['magnet'][] = [ - 'status' => false, - 'message' => sprintf( - _('Magnet data mismatch protocol with error: %s'), - print_r($error, true) - ), - ]; - - continue 2; - } - - // User local alias required - if (!isset($aliasUserId[$remote->userId])) - { - $response['magnet'][] = [ - 'status' => false, - 'message' => _('User data relation not found for magnet'), - ]; - - continue 2; - } - - // Skip import on magnet approved required - if (API_IMPORT_MAGNETS_APPROVED_ONLY && !$remote->approved) - { - $response['magnet'][] = [ - 'status' => false, - 'message' => _('Node accepting approved magnets only') - ]; - - continue 2; - } - - /// Add new magnet if not exist by timestamp added for this user - if ($local = $db->findMagnet($aliasUserId[$remote->userId], $remote->timeAdded)) - { - $response['magnet'][] = [ - 'status' => true, - 'message' => sprintf( - _('Magnet successfully associated with ID "%s"'), - $local->magnetId - ) - ]; - } - - /// Add and init new magnet if not exist - else if ($local = $db->getMagnet( - $db->addMagnet( - $aliasUserId[$remote->userId], - $remote->xl, - $remote->dn, - '', // @TODO linkSource used for debug only, will be deleted later - true, - $remote->comments, - $remote->sensitive, - MAGNET_AUTO_APPROVE_ON_IMPORT_APPROVED ? $remote->approved : MAGNET_DEFAULT_APPROVED, - $remote->timeAdded - ) - ) - ) - { - $response['magnet'][] = [ - 'status' => true, - 'message' => sprintf( - _('Magnet successfully synced with ID "%s"'), - $local->magnetId - ) - ]; - } - - else - { - $response['magnet'][] = [ - 'status' => false, - 'message' => sprintf( - _('Could not init magnet: %s'), - $remote - ) - ]; - - continue 2; - } - - /// Add magnet alias for this host - $aliasMagnetId[$remote->magnetId] = $local->magnetId; - - /// Update time added if newer - if ($local->timeAdded < $remote->timeAdded) - { - $db->updateMagnetTimeAdded( - $local->magnetId, - $remote->timeAdded - ); - - $response['magnet'][] = [ - 'status' => true, - 'message' => sprintf( - _('Field "timeAdded" changed to newer value for magnet ID "%s"'), - $local->magnetId - ) - ]; - } - - /// Update info if remote newer - if ($local->timeUpdated < $remote->timeUpdated) - { - // Magnet fields - $db->updateMagnetXl($local->magnetId, $remote->xl, $remote->timeUpdated); - $db->updateMagnetDn($local->magnetId, $remote->dn, $remote->timeUpdated); - $db->updateMagnetTitle($local->magnetId, $remote->title, $remote->timeUpdated); - $db->updateMagnetPreview($local->magnetId, $remote->preview, $remote->timeUpdated); - $db->updateMagnetDescription($local->magnetId, $remote->description, $remote->timeUpdated); - $db->updateMagnetComments($local->magnetId, $remote->comments, $remote->timeUpdated); - $db->updateMagnetSensitive($local->magnetId, $remote->sensitive, $remote->timeUpdated); - - if (MAGNET_AUTO_APPROVE_ON_IMPORT_APPROVED && $local->approved !== $remote->approved && $remote->approved) - { - $db->updateMagnetApproved($local->magnetId, $remote->approved, $remote->timeUpdated); - } - - // xt - foreach ((array) $remote->xt as $xt) - { - switch ($xt->version) - { - case 1: - - $exist = false; - - foreach ($db->findMagnetToInfoHashByMagnetId($local->magnetId) as $result) - { - if ($infoHash = $db->getInfoHash($result->infoHashId)) - { - if ($infoHash->version == 1) - { - $exist = true; - } - } - } - - if (!$exist) - { - $db->addMagnetToInfoHash( - $local->magnetId, - $db->initInfoHashId( - $xt->value, 1 - ) - ); - } - - break; - - case 2: - - $exist = false; - - foreach ($db->findMagnetToInfoHashByMagnetId($local->magnetId) as $result) - { - if ($infoHash = $db->getInfoHash($result->infoHashId)) - { - if ($infoHash->version == 2) - { - $exist = true; - } - } - } - - if (!$exist) - { - $db->addMagnetToInfoHash( - $local->magnetId, - $db->initInfoHashId( - $xt->value, 2 - ) - ); - } - - break; - } - } - - // kt - $db->deleteMagnetToKeywordTopicByMagnetId($local->magnetId); - - foreach ($remote->kt as $kt) - { - $db->initMagnetToKeywordTopicId( - $local->magnetId, - $db->initKeywordTopicId(trim(mb_strtolower($kt))) - ); - } - - // tr - $db->deleteMagnetToAddressTrackerByMagnetId($local->magnetId); - - foreach ($remote->tr as $tr) - { - if ($url = Yggverse\Parser\Url::parse($tr)) - { - $db->initMagnetToAddressTrackerId( - $local->magnetId, - $db->initAddressTrackerId( - $db->initSchemeId($url->host->scheme), - $db->initHostId($url->host->name), - $db->initPortId($url->host->port), - $db->initUriId($url->page->uri) - ) - ); - } - } - - // as - $db->deleteMagnetToAcceptableSourceByMagnetId($local->magnetId); - - foreach ($remote->as as $as) - { - if ($url = Yggverse\Parser\Url::parse($as)) - { - $db->initMagnetToAcceptableSourceId( - $local->magnetId, - $db->initAcceptableSourceId( - $db->initSchemeId($url->host->scheme), - $db->initHostId($url->host->name), - $db->initPortId($url->host->port), - $db->initUriId($url->page->uri) - ) - ); - } - } - - // xs - $db->deleteMagnetToExactSourceByMagnetId($local->magnetId); - - foreach ($remote->xs as $xs) - { - if ($url = Yggverse\Parser\Url::parse($xs)) - { - $db->initMagnetToExactSourceId( - $local->magnetId, - $db->initExactSourceId( - $db->initSchemeId($url->host->scheme), - $db->initHostId($url->host->name), - $db->initPortId($url->host->port), - $db->initUriId($url->page->uri) - ) - ); - } - } - - $response['magnet'][] = [ - 'status' => true, - 'message' => sprintf( - _('Magnet fields updated to newer version for magnet ID "%s"'), - $local->magnetId - ) - ]; - } - - break; - case 'magnetComment': - - if (!API_IMPORT_MAGNET_COMMENTS_ENABLED) - { - $response['magnetComment'][] = [ - 'status' => false, - 'message' => _('Magnet comments import disabled on this node') - ]; - - continue 2; - } - - // Validate - $error = []; - - if (!Valid::magnetComment($remote, $error)) - { - $response['magnetComment'][] = [ - 'status' => false, - 'message' => sprintf( - _('Magnet comment data mismatch protocol with error: %s'), - print_r($error, true) - ), - ]; - - continue 2; - } - - // Skip import on magnet approved required - if (API_IMPORT_MAGNET_COMMENTS_APPROVED_ONLY && !$remote->approved) - { - $response['magnetComment'][] = [ - 'status' => false, - 'message' => _('Node accepting approved magnet comments only: %s') - ]; - - continue 2; - } - - // User local alias required - if (!isset($aliasUserId[$remote->userId]) || !isset($aliasMagnetId[$remote->magnetId])) - { - $response['magnetComment'][] = [ - 'status' => false, - 'message' => _('Magnet comment data relation not found for: %s') - ]; - - continue 2; - } - - // Parent comment provided - if (is_int($remote->magnetCommentIdParent)) - { - $localMagnetCommentIdParent = null; // @TODO feature not in use yet - } - - else - { - $localMagnetCommentIdParent = null; - } - - // Magnet comment exists by timestamp added for this user - if ($local = $db->findMagnetComment($aliasMagnetId[$remote->magnetId], - $aliasUserId[$remote->userId], - $remote->timeAdded)) - { - $response['magnetComment'][] = [ - 'status' => true, - 'message' => sprintf( - _('Magnet comment successfully associated with ID "%s"'), - $local->magnetCommentId - ) - ]; - } - - // Magnet comment exists by timestamp added for this user, register new one - else if ($magnetCommentId = $db->addMagnetComment($aliasMagnetId[$remote->magnetId], - $aliasUserId[$remote->userId], - $localMagnetCommentIdParent, - $remote->value, - $remote->approved, - true, - $remote->timeAdded)) - { - $response['magnetComment'][] = [ - 'status' => true, - 'message' => sprintf( - _('Magnet comment successfully synced with ID "%s"'), - $magnetCommentId - ) - ]; - } - - break; - case 'magnetDownload': - - // Magnet downloads - if (!API_IMPORT_MAGNET_DOWNLOADS_ENABLED) - { - $response['magnetDownload'][] = [ - 'status' => false, - 'message' => _('Magnet downloads import disabled on this node') - ]; - - continue 2; - } - - // Validate - $error = []; - - if (!Valid::magnetDownload($remote, $error)) - { - $response['magnetDownload'][] = [ - 'status' => false, - 'message' => sprintf( - _('Magnet download data mismatch protocol with error: %s'), - print_r($error, true) - ), - ]; - - continue 2; - } - - // User local alias required - if (!isset($aliasUserId[$remote->userId]) || !isset($aliasMagnetId[$remote->magnetId])) - { - $response['magnetDownload'][] = [ - 'status' => false, - 'message' => _('Magnet download data relation not found') - ]; - - continue 2; - } - - // Magnet download exists by timestamp added for this user - if ($local = $db->findMagnetDownload($aliasMagnetId[$remote->magnetId], - $aliasUserId[$remote->userId], - $remote->timeAdded)) - { - $response['magnetDownload'][] = [ - 'status' => true, - 'message' => sprintf( - _('Magnet download successfully associated with ID "%s"'), - $local->magnetDownloadId - ) - ]; - } - - // Magnet download exists by timestamp added for this user, register new one - else if ($magnetDownloadId = $db->addMagnetDownload($aliasMagnetId[$remote->magnetId], - $aliasUserId[$remote->userId], - $remote->timeAdded)) - { - $response['magnetDownload'][] = [ - 'status' => true, - 'message' => sprintf( - _('Magnet download successfully synced with ID "%s"'), - $magnetDownloadId - ) - ]; - } - - break; - case 'magnetStar': - - if (!API_IMPORT_MAGNET_STARS_ENABLED) - { - $response['magnetStar'][] = [ - 'status' => false, - 'message' => _('Magnet stars import disabled on this node') - ]; - - continue 2; - } - - // Validate - $error = []; - - if (!Valid::magnetStar($remote, $error)) - { - $response['magnetStar'][] = [ - 'status' => false, - 'message' => sprintf( - _('Magnet star data mismatch protocol with error: %s'), - print_r($error, true) - ), - ]; - - continue 2; - } - - // User local alias required - if (!isset($aliasUserId[$remote->userId]) || !isset($aliasMagnetId[$remote->magnetId])) - { - $response['magnetStar'][] = [ - 'status' => false, - 'message' => _('Magnet star data relation not found') - ]; - - continue 2; - } - - // Magnet star exists by timestamp added for this user - if ($local = $db->findMagnetStar($aliasMagnetId[$remote->magnetId], - $aliasUserId[$remote->userId], - $remote->timeAdded)) - { - $response['magnetStar'][] = [ - 'status' => true, - 'message' => sprintf( - _('Magnet star successfully associated with ID "%s"'), - $local->magnetStarId - ) - ]; - } - - // Magnet star exists by timestamp added for this user, register new one - else if ($magnetStarId = $db->addMagnetStar($aliasMagnetId[$remote->magnetId], - $aliasUserId[$remote->userId], - $remote->value, - $remote->timeAdded)) - { - $response['magnetStar'][] = [ - 'status' => true, - 'message' => sprintf( - _('Magnet star successfully synced with ID "%s"'), - $magnetStarId - ) - ]; - } - - break; - case 'magnetView': - - if (!API_IMPORT_MAGNET_VIEWS_ENABLED) - { - $response['magnetView'][] = [ - 'status' => false, - 'message' => _('Magnet views import disabled on this node') - ]; - - continue 2; - } - - // Validate - $error = []; - - if (!Valid::magnetView($remote, $error)) - { - $response['magnetView'][] = [ - 'status' => false, - 'message' => sprintf( - _('Magnet view data mismatch protocol with error: %s'), - print_r($error, true) - ), - ]; - - continue 2; - } - - // User local alias required - if (!isset($aliasUserId[$remote->userId]) || !isset($aliasMagnetId[$remote->magnetId])) - { - $response['magnetView'][] = [ - 'status' => false, - 'message' => _('Magnet view data relation not found for: %s') - ]; - - continue 2; - } - - // Magnet view exists by timestamp added for this user - if ($local = $db->findMagnetView($aliasMagnetId[$remote->magnetId], - $aliasUserId[$remote->userId], - $remote->timeAdded)) - { - $response['magnetView'][] = [ - 'status' => true, - 'message' => sprintf( - _('Magnet view successfully associated with ID "%s"'), - $local->magnetViewId - ) - ]; - } - - // Magnet view exists by timestamp added for this user, register new one - else if ($magnetViewId = $db->addMagnetView($aliasMagnetId[$remote->magnetId], - $aliasUserId[$remote->userId], - $remote->timeAdded)) - { - $response['magnetView'][] = [ - 'status' => true, - 'message' => sprintf( - _('Magnet view successfully synced with ID "%s"'), - $magnetViewId - ) - ]; - } - - break; - default: - - $response[$field][] = - [ - 'status' => false, - 'message' => _('Field "%s" not supported by protocol') - ]; - - continue 2; - } - } - - $db->commit(); - } - - catch (Exception $error) - { - $debug['exception'][] = print_r($error, true); - - $db->rollBack(); - } -} - -// Debug log -if (LOG_API_PUSH_ENABLED) -{ - @mkdir(LOG_DIRECTORY, 0770, true); - - if ($handle = fopen(LOG_DIRECTORY . '/' . LOG_API_PUSH_FILENAME, 'a+')) - { - $debug['time']['total'] = microtime(true) - $debug['time']['total']; - - $debug['memory']['total'] = memory_get_usage() - $debug['memory']['start']; - $debug['memory']['peaks'] = memory_get_peak_usage(); - - $debug['db']['total']['select'] = $db->getDebug()->query->select->total; - $debug['db']['total']['insert'] = $db->getDebug()->query->insert->total; - $debug['db']['total']['update'] = $db->getDebug()->query->update->total; - $debug['db']['total']['delete'] = $db->getDebug()->query->delete->total; - - fwrite( - $handle, - print_r( - [ - 'response' => $response, - 'debug' => $debug - ], - true - ) - ); - - fclose($handle); - - chmod(LOG_DIRECTORY . '/' . LOG_API_PUSH_FILENAME, 0770); - } -} - -// Output -header('Content-Type: application/json; charset=utf-8'); - -echo json_encode($response); \ No newline at end of file diff --git a/src/public/index.php b/src/public/index.php deleted file mode 100644 index 6a9b6e3..0000000 --- a/src/public/index.php +++ /dev/null @@ -1,4 +0,0 @@ - + + + + {% block title %}Welcome!{% endblock %} + + {% block stylesheets %} + {% endblock %} + + {% block javascripts %} + {% endblock %} + + + {% block body %}{% endblock %} + + diff --git a/templates/default/home/index.html.twig b/templates/default/home/index.html.twig new file mode 100644 index 0000000..fe403d6 --- /dev/null +++ b/templates/default/home/index.html.twig @@ -0,0 +1,2 @@ +{% extends 'default/layout.html.twig' %} +{% block title %}{{ 'Home'|trans }} - {{ name }}{% endblock %} \ No newline at end of file diff --git a/templates/default/layout.html.twig b/templates/default/layout.html.twig new file mode 100644 index 0000000..58b2433 --- /dev/null +++ b/templates/default/layout.html.twig @@ -0,0 +1,60 @@ + + + + + {% block title %}{{ name }}{% endblock %} + {% block stylesheets %} + + + {% endblock %} + + + {% block header %} +
+
+
+ + {% block header_search %} + {{ render(controller( + 'App\\Controller\\SearchController::module' + )) }} + {% endblock %} +
+
+
+ {% endblock %} + {% block main %} +
+
+
+
+ {% block main_profile %} + {{ render(controller( + 'App\\Controller\\ProfileController::module', + {route : app.request.get('_route')} + )) }} + {% endblock %} +
+ {% block main_content %}{% endblock %} +
+
+
+
+
+ {% endblock %} + {% block footer %} +
+
+
+
+ {% block footer_trackers %}{% endblock %} + GitHub +
+
+
+
+ {% endblock %} + + diff --git a/templates/default/page/submit.html.twig b/templates/default/page/submit.html.twig new file mode 100644 index 0000000..736ec81 --- /dev/null +++ b/templates/default/page/submit.html.twig @@ -0,0 +1,129 @@ +{% extends 'default/layout.html.twig' %} +{% block title %}{{'Submit'|trans }} - {{ name }}{% endblock %} + +{% block main_content %} +
+

{{'Submit'|trans }}

+
+
+ +
+ + + + + + + +
+
+ + + + + + + {% for errors in form.title.error %} + {% for error in errors %} +
+ {{ error }} +
+ {% endfor %} + {% endfor %} + +
+
+ + + + + + + {% for errors in form.description.error %} + {% for error in errors %} +
+ {{ error }} +
+ {% endfor %} + {% endfor %} + +
+
+ + + + + + + {% for errors in form.keywords.error %} + {% for error in errors %} +
+ {{ error }} +
+ {% endfor %} + {% endfor %} + +
+
+ + + + + + + +
+
+ +
+
+{% endblock %} diff --git a/templates/default/profile/index.html.twig b/templates/default/profile/index.html.twig new file mode 100644 index 0000000..34c7353 --- /dev/null +++ b/templates/default/profile/index.html.twig @@ -0,0 +1,2 @@ +{% extends 'default/layout.html.twig' %} +{% block title %}{{ 'Profile - Settings'|trans }} - {{ name }}{% endblock %} \ No newline at end of file diff --git a/src/app/view/theme/default/module/profile.phtml b/templates/default/profile/module.html.twig similarity index 52% rename from src/app/view/theme/default/module/profile.phtml rename to templates/default/profile/module.html.twig index 5d54747..2277622 100644 --- a/src/app/view/theme/default/module/profile.phtml +++ b/templates/default/profile/module.html.twig @@ -1,199 +1,178 @@ -
-
- - identicon - +
+ -
- - +
+ {% if route == 'home_index' %} + - - + + {{ 'Home'|trans }} - - + {% else %} + - - + + {{ 'Home'|trans }} - - - - + {% endif %} + {% if route == 'page_stars' %} + - - + + {{ 'Stars'|trans }} - + {{ stars }} - - + {% else %} + - - + + {{ 'Stars'|trans }} - + {{ stars }} - - - + {% endif %} + {% if route == 'page_views' %} + - - + + {{ 'Views'|trans }} - + {{ views }} - - + {% else %} + - - + + {{ 'Views'|trans }} - + {{ views }} - - - + {% endif %} + {% if route == 'page_comments' %} + - - + + {{ 'Comments'|trans }} - + {{ comments }} - - + {% else %} + - - + + {{ 'Comments'|trans }} - + {{ comments }} - - - + {% endif %} + {% if route == 'page_downloads' %} + - - + + {{ 'Downloads'|trans }} - + {{ downloads }} - - + {% else %} + - - + + {{ 'Downloads'|trans }} - + {{ downloads }} - - - + {% endif %} + {% if route == 'page_editions' %} + - - + + {{ 'Editions'|trans }} - + {{ editions }} - - + {% else %} + - - + + {{ 'Editions'|trans }} - + {{ editions }} - - - + {% endif %} + {% if route == '/page/submit' %} + - - + + {{ 'Submit'|trans }} - - + {% else %} + - - + + {{ 'Submit'|trans }} - + {% endif %}
\ No newline at end of file diff --git a/templates/default/profile/setting.html.twig b/templates/default/profile/setting.html.twig new file mode 100644 index 0000000..34c7353 --- /dev/null +++ b/templates/default/profile/setting.html.twig @@ -0,0 +1,2 @@ +{% extends 'default/layout.html.twig' %} +{% block title %}{{ 'Profile - Settings'|trans }} - {{ name }}{% endblock %} \ No newline at end of file diff --git a/templates/default/search/index.html.twig b/templates/default/search/index.html.twig new file mode 100644 index 0000000..9ede45e --- /dev/null +++ b/templates/default/search/index.html.twig @@ -0,0 +1,10 @@ +{% extends 'default/layout.html.twig' %} +{% block title %}{{ query }} - {{'Search'|trans }} - {{ name }}{% endblock %} +{% block header_search %} + {{ render(controller( + 'App\\Controller\\SearchController::module', + { + query : query + } + )) }} +{% endblock %} \ No newline at end of file diff --git a/templates/default/search/module.html.twig b/templates/default/search/module.html.twig new file mode 100644 index 0000000..f872234 --- /dev/null +++ b/templates/default/search/module.html.twig @@ -0,0 +1,4 @@ +
+ + +
\ No newline at end of file diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..469dcce --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,11 @@ +bootEnv(dirname(__DIR__).'/.env'); +} diff --git a/translations/.gitignore b/translations/.gitignore new file mode 100644 index 0000000..e69de29