From f1f73564a071e7cab200bd8f2ab6f90677b65131 Mon Sep 17 00:00:00 2001 From: Arsen Mirzaev Tatyano-Muradovich Date: Mon, 9 Mar 2026 22:06:33 +0500 Subject: [PATCH] deals, project maker and sex --- composer.json | 12 +- composer.lock | 4342 +---------------- .../databases/scripts/administrator.php | 77 + .../system/localizations/russian.php | 151 +- .../constructor/system/models/account.php | 25 +- .../system/models/authorizations.php | 19 +- kodorvan/constructor/system/models/deal.php | 240 + .../models/deal/enumerations/direction.php | 23 + .../constructor/system/models/project.php | 302 +- .../project/enumerations/integration.php | 64 +- .../models/project/enumerations/purpose.php | 4 +- .../models/project/enumerations/status.php | 4 - .../system/models/telegram/commands/start.php | 40 +- .../{project/create.php => project.php} | 935 ++-- .../system/models/telegram/exceptions.php | 48 + .../system/models/telegram/project.php | 278 +- kodorvan/constructor/system/public/index.php | 52 - .../public/telegram/constructor/webhook.php | 130 +- 18 files changed, 1884 insertions(+), 4862 deletions(-) create mode 100644 kodorvan/constructor/system/databases/scripts/administrator.php create mode 100644 kodorvan/constructor/system/models/deal.php create mode 100644 kodorvan/constructor/system/models/deal/enumerations/direction.php rename kodorvan/constructor/system/models/telegram/conversations/{project/create.php => project.php} (65%) create mode 100644 kodorvan/constructor/system/models/telegram/exceptions.php delete mode 100644 kodorvan/constructor/system/public/index.php diff --git a/composer.json b/composer.json index 120c991..05ba737 100644 --- a/composer.json +++ b/composer.json @@ -23,18 +23,13 @@ }, "require": { "php": "^8.5", - "mirzaev/minimal": "^3.7", - "mirzaev/baza": "^3.4", - "mirzaev/record": "^1.0", + "mirzaev/minimal": "^3", + "mirzaev/baza": "^3", + "mirzaev/record": "^2.0", "mirzaev/languages": "^1.0", "mirzaev/currencies": "^2.0", "mirzaev/unmarkdown": "^1.0", "svoboda/time": "^1.0", - "badfarm/zanzara": "^0.9.1", - "twig/twig": "^3.2", - "twig/extra-bundle": "^3.7", - "twig/intl-extra": "^3.10", - "react/filesystem": "^0.1.2", "nyholm/psr7": "^1.8", "irazasyed/telegram-bot-sdk": "^3.15", "nutgram/nutgram": "^4.42", @@ -44,7 +39,6 @@ "suggest": { "mirzaev/files": "Easy working with files", "mirzaev/currencies": "Easy currencies integration" - }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index ffb5173..3764f89 100644 --- a/composer.lock +++ b/composer.lock @@ -4,193 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "44219ee87ec9e34c98a5404150eb4ac0", + "content-hash": "cea85cd4ee9c4b5548011051487f4b81", "packages": [ - { - "name": "badfarm/zanzara", - "version": "0.9.1", - "source": { - "type": "git", - "url": "https://github.com/badfarm/zanzara.git", - "reference": "de4f3df9006d7e7cce0c15033dceafbad9348576" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/badfarm/zanzara/zipball/de4f3df9006d7e7cce0c15033dceafbad9348576", - "reference": "de4f3df9006d7e7cce0c15033dceafbad9348576", - "shasum": "" - }, - "require": { - "clue/http-proxy-react": "^1.8", - "ext-json": "*", - "ext-readline": "*", - "netresearch/jsonmapper": "^4.1", - "opis/closure": "^3.6", - "php": ">=7.4", - "php-di/php-di": "^6.4", - "php-http/multipart-stream-builder": "^1.2", - "psr/container": "^1.1", - "psr/log": "^1.1", - "react/cache": "^1.2", - "react/event-loop": "^1.3", - "react/http": "^1.8" - }, - "require-dev": { - "monolog/monolog": "^2.9", - "phpunit/phpunit": "^9.6", - "symfony/dotenv": "^5.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Zanzara\\": "src/Zanzara" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michele Righetti" - }, - { - "name": "Mattia Corradi" - } - ], - "description": "Asynchronous PHP Telegram Bot Framework", - "keywords": [ - "async", - "bot", - "php", - "reactphp", - "telegram" - ], - "support": { - "issues": "https://github.com/badfarm/zanzara/issues", - "source": "https://github.com/badfarm/zanzara/tree/0.9.1" - }, - "time": "2023-04-25T18:44:20+00:00" - }, - { - "name": "cakephp/core", - "version": "4.6.3", - "source": { - "type": "git", - "url": "https://github.com/cakephp/core.git", - "reference": "c2f4dff110d41e475d1041f2abe236f1c62d0cd0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/cakephp/core/zipball/c2f4dff110d41e475d1041f2abe236f1c62d0cd0", - "reference": "c2f4dff110d41e475d1041f2abe236f1c62d0cd0", - "shasum": "" - }, - "require": { - "cakephp/utility": "^4.0", - "php": ">=7.4.0" - }, - "provide": { - "psr/container-implementation": "^1.0 || ^2.0" - }, - "suggest": { - "cakephp/cache": "To use Configure::store() and restore().", - "cakephp/event": "To use PluginApplicationInterface or plugin applications.", - "league/container": "To use Container and ServiceProvider classes" - }, - "type": "library", - "autoload": { - "files": [ - "functions.php" - ], - "psr-4": { - "Cake\\Core\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "CakePHP Community", - "homepage": "https://github.com/cakephp/core/graphs/contributors" - } - ], - "description": "CakePHP Framework Core classes", - "homepage": "https://cakephp.org", - "keywords": [ - "cakephp", - "core", - "framework" - ], - "support": { - "forum": "https://stackoverflow.com/tags/cakephp", - "irc": "irc://irc.freenode.org/cakephp", - "issues": "https://github.com/cakephp/cakephp/issues", - "source": "https://github.com/cakephp/core" - }, - "time": "2023-10-21T13:30:46+00:00" - }, - { - "name": "cakephp/utility", - "version": "4.6.3", - "source": { - "type": "git", - "url": "https://github.com/cakephp/utility.git", - "reference": "708929115e5b400e1b5b76d8120ca2e51e2de199" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/cakephp/utility/zipball/708929115e5b400e1b5b76d8120ca2e51e2de199", - "reference": "708929115e5b400e1b5b76d8120ca2e51e2de199", - "shasum": "" - }, - "require": { - "cakephp/core": "^4.0", - "php": ">=7.4.0" - }, - "suggest": { - "ext-intl": "To use Text::transliterate() or Text::slug()", - "lib-ICU": "To use Text::transliterate() or Text::slug()" - }, - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Cake\\Utility\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "CakePHP Community", - "homepage": "https://github.com/cakephp/utility/graphs/contributors" - } - ], - "description": "CakePHP Utility classes such as Inflector, String, Hash, and Security", - "homepage": "https://cakephp.org", - "keywords": [ - "cakephp", - "hash", - "inflector", - "security", - "string", - "utility" - ], - "support": { - "forum": "https://stackoverflow.com/tags/cakephp", - "irc": "irc://irc.freenode.org/cakephp", - "issues": "https://github.com/cakephp/cakephp/issues", - "source": "https://github.com/cakephp/utility" - }, - "time": "2024-06-23T00:11:14+00:00" - }, { "name": "carbonphp/carbon-doctrine-types", "version": "3.2.0", @@ -260,74 +75,6 @@ ], "time": "2024-02-09T16:56:22+00:00" }, - { - "name": "clue/http-proxy-react", - "version": "v1.9.0", - "source": { - "type": "git", - "url": "https://github.com/clue/reactphp-http-proxy.git", - "reference": "f3b02835273036a9370ac1c144b55df8e2b98430" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/clue/reactphp-http-proxy/zipball/f3b02835273036a9370ac1c144b55df8e2b98430", - "reference": "f3b02835273036a9370ac1c144b55df8e2b98430", - "shasum": "" - }, - "require": { - "php": ">=5.3", - "react/promise": "^3 || ^2.1 || ^1.2.1", - "react/socket": "^1.12", - "ringcentral/psr7": "^1.2" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "react/async": "^4 || ^3 || ^2", - "react/event-loop": "^1.2", - "react/http": "^1.5", - "react/promise-timer": "^1.10" - }, - "type": "library", - "autoload": { - "psr-4": { - "Clue\\React\\HttpProxy\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering" - } - ], - "description": "Async HTTP proxy connector, tunnel any TCP/IP-based protocol through an HTTP CONNECT proxy server, built on top of ReactPHP", - "homepage": "https://github.com/clue/reactphp-http-proxy", - "keywords": [ - "async", - "connect", - "http", - "proxy", - "reactphp" - ], - "support": { - "issues": "https://github.com/clue/reactphp-http-proxy/issues", - "source": "https://github.com/clue/reactphp-http-proxy/tree/v1.9.0" - }, - "funding": [ - { - "url": "https://clue.engineering/support", - "type": "custom" - }, - { - "url": "https://github.com/clue", - "type": "github" - } - ], - "time": "2024-04-10T14:46:11+00:00" - }, { "name": "doctrine/inflector", "version": "2.1.0", @@ -418,178 +165,6 @@ ], "time": "2025-08-10T19:31:58+00:00" }, - { - "name": "doctrine/instantiator", - "version": "2.1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "23da848e1a2308728fe5fdddabf4be17ff9720c7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/23da848e1a2308728fe5fdddabf4be17ff9720c7", - "reference": "23da848e1a2308728fe5fdddabf4be17ff9720c7", - "shasum": "" - }, - "require": { - "php": "^8.4" - }, - "require-dev": { - "doctrine/coding-standard": "^14", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^1.2", - "phpstan/phpstan": "^2.1", - "phpstan/phpstan-phpunit": "^2.0", - "phpunit/phpunit": "^10.5.58" - }, - "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.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%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2026-01-05T06:47:08+00:00" - }, - { - "name": "evenement/evenement", - "version": "v3.0.2", - "source": { - "type": "git", - "url": "https://github.com/igorw/evenement.git", - "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", - "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", - "shasum": "" - }, - "require": { - "php": ">=7.0" - }, - "require-dev": { - "phpunit/phpunit": "^9 || ^6" - }, - "type": "library", - "autoload": { - "psr-4": { - "Evenement\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" - } - ], - "description": "Événement is a very simple event dispatching library for PHP", - "keywords": [ - "event-dispatcher", - "event-emitter" - ], - "support": { - "issues": "https://github.com/igorw/evenement/issues", - "source": "https://github.com/igorw/evenement/tree/v3.0.2" - }, - "time": "2023-08-08T05:53:35+00:00" - }, - { - "name": "fig/http-message-util", - "version": "1.1.5", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message-util.git", - "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", - "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", - "shasum": "" - }, - "require": { - "php": "^5.3 || ^7.0 || ^8.0" - }, - "suggest": { - "psr/http-message": "The package containing the PSR-7 interfaces" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Fig\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "issues": "https://github.com/php-fig/http-message-util/issues", - "source": "https://github.com/php-fig/http-message-util/tree/1.1.5" - }, - "time": "2020-11-24T22:02:12+00:00" - }, { "name": "guzzlehttp/guzzle", "version": "7.10.0", @@ -917,16 +492,16 @@ }, { "name": "illuminate/collections", - "version": "v12.49.0", + "version": "v12.53.0", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", - "reference": "18ca56ad53265a18508198473b1523c1ad46edad" + "reference": "f35c084f0d9bc57895515cb4d0665797c66285fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/collections/zipball/18ca56ad53265a18508198473b1523c1ad46edad", - "reference": "18ca56ad53265a18508198473b1523c1ad46edad", + "url": "https://api.github.com/repos/illuminate/collections/zipball/f35c084f0d9bc57895515cb4d0665797c66285fd", + "reference": "f35c084f0d9bc57895515cb4d0665797c66285fd", "shasum": "" }, "require": { @@ -973,11 +548,11 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2026-01-23T16:02:04+00:00" + "time": "2026-02-16T14:10:38+00:00" }, { "name": "illuminate/conditionable", - "version": "v12.49.0", + "version": "v12.53.0", "source": { "type": "git", "url": "https://github.com/illuminate/conditionable.git", @@ -1023,16 +598,16 @@ }, { "name": "illuminate/contracts", - "version": "v12.49.0", + "version": "v12.53.0", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", - "reference": "2c0015e16b40f32c41e49810b6a0acf61204ea3d" + "reference": "099fd9b56ccaf776facaa27699b960a3f2451127" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/contracts/zipball/2c0015e16b40f32c41e49810b6a0acf61204ea3d", - "reference": "2c0015e16b40f32c41e49810b6a0acf61204ea3d", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/099fd9b56ccaf776facaa27699b960a3f2451127", + "reference": "099fd9b56ccaf776facaa27699b960a3f2451127", "shasum": "" }, "require": { @@ -1067,11 +642,11 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2026-01-07T14:57:06+00:00" + "time": "2026-02-20T14:37:40+00:00" }, { "name": "illuminate/macroable", - "version": "v12.49.0", + "version": "v12.53.0", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", @@ -1117,16 +692,16 @@ }, { "name": "illuminate/reflection", - "version": "v12.49.0", + "version": "v12.53.0", "source": { "type": "git", "url": "https://github.com/illuminate/reflection.git", - "reference": "7b86bc570d5b75e4a3ad79f8cca1491ba24b7c75" + "reference": "6188e97a587371b9951c2a7e337cd760308c17d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/reflection/zipball/7b86bc570d5b75e4a3ad79f8cca1491ba24b7c75", - "reference": "7b86bc570d5b75e4a3ad79f8cca1491ba24b7c75", + "url": "https://api.github.com/repos/illuminate/reflection/zipball/6188e97a587371b9951c2a7e337cd760308c17d7", + "reference": "6188e97a587371b9951c2a7e337cd760308c17d7", "shasum": "" }, "require": { @@ -1164,20 +739,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-12-09T15:11:22+00:00" + "time": "2026-02-04T15:21:22+00:00" }, { "name": "illuminate/support", - "version": "v12.49.0", + "version": "v12.53.0", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "196cae049b187ebffbe72efd22ef3ae57dd0a2db" + "reference": "18d7d75366ddb9eded3b7f05173f791da47faf34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/196cae049b187ebffbe72efd22ef3ae57dd0a2db", - "reference": "196cae049b187ebffbe72efd22ef3ae57dd0a2db", + "url": "https://api.github.com/repos/illuminate/support/zipball/18d7d75366ddb9eded3b7f05173f791da47faf34", + "reference": "18d7d75366ddb9eded3b7f05173f791da47faf34", "shasum": "" }, "require": { @@ -1244,7 +819,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2026-01-27T02:58:23+00:00" + "time": "2026-02-23T15:44:06+00:00" }, { "name": "irazasyed/telegram-bot-sdk", @@ -1331,32 +906,32 @@ }, { "name": "laravel/serializable-closure", - "version": "v1.3.7", + "version": "v2.0.10", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "4f48ade902b94323ca3be7646db16209ec76be3d" + "reference": "870fc81d2f879903dfc5b60bf8a0f94a1609e669" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/4f48ade902b94323ca3be7646db16209ec76be3d", - "reference": "4f48ade902b94323ca3be7646db16209ec76be3d", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/870fc81d2f879903dfc5b60bf8a0f94a1609e669", + "reference": "870fc81d2f879903dfc5b60bf8a0f94a1609e669", "shasum": "" }, "require": { - "php": "^7.3|^8.0" + "php": "^8.1" }, "require-dev": { - "illuminate/support": "^8.0|^9.0|^10.0|^11.0", - "nesbot/carbon": "^2.61|^3.0", - "pestphp/pest": "^1.21.3", - "phpstan/phpstan": "^1.8.2", - "symfony/var-dumper": "^5.4.11|^6.2.0|^7.0.0" + "illuminate/support": "^10.0|^11.0|^12.0|^13.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0|^4.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0|^8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { @@ -1388,7 +963,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2024-11-14T18:34:49+00:00" + "time": "2026-02-20T19:59:49+00:00" }, { "name": "league/event", @@ -1625,11 +1200,11 @@ }, { "name": "mirzaev/record", - "version": "1.1.1", + "version": "2.1.2", "source": { "type": "git", "url": "https://git.svoboda.works/mirzaev/record", - "reference": "14c2629fb34b1ca1a852712069687dff69050786" + "reference": "670d7a07307fa461648a3641b93d5b66aa1df560" }, "require": { "mirzaev/baza": "^3.4", @@ -1663,15 +1238,15 @@ "issues": "https://git.svoboda.works/mirzaev/record/issues", "wiki": "https://git.svoboda.works/mirzaev/record/wiki" }, - "time": "2025-11-03T19:07:01+00:00" + "time": "2025-12-24T17:23:00+00:00" }, { "name": "mirzaev/unmarkdown", - "version": "1.0.3", + "version": "1.0.5", "source": { "type": "git", "url": "https://git.svoboda.works/mirzaev/unmarkdown", - "reference": "ae97b9e4644dc591965694570277cdafdc46247d" + "reference": "a0309030f65b024b8a35cd60fba396f6b8e063ee" }, "require": { "php": "^8.4" @@ -1703,7 +1278,7 @@ "support": { "issues": "https://git.svoboda.works/mirzaev/unmarkdown/issues" }, - "time": "2025-11-09T11:37:20+00:00" + "time": "2026-01-14T10:49:12+00:00" }, { "name": "nesbot/carbon", @@ -1810,57 +1385,6 @@ ], "time": "2026-01-29T09:26:29+00:00" }, - { - "name": "netresearch/jsonmapper", - "version": "v4.5.0", - "source": { - "type": "git", - "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8e76efb98ee8b6afc54687045e1b8dba55ac76e5", - "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0", - "squizlabs/php_codesniffer": "~3.5" - }, - "type": "library", - "autoload": { - "psr-0": { - "JsonMapper": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "OSL-3.0" - ], - "authors": [ - { - "name": "Christian Weiske", - "email": "cweiske@cweiske.de", - "homepage": "http://github.com/cweiske/jsonmapper/", - "role": "Developer" - } - ], - "description": "Map nested JSON structures onto PHP classes", - "support": { - "email": "cweiske@cweiske.de", - "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.5.0" - }, - "time": "2024-09-08T10:13:13+00:00" - }, { "name": "nutgram/hydrator", "version": "7.0.2", @@ -1923,16 +1447,16 @@ }, { "name": "nutgram/nutgram", - "version": "4.42.0", + "version": "4.44.0", "source": { "type": "git", "url": "https://github.com/nutgram/nutgram.git", - "reference": "034257dbc29947b73e04b5d92b07d780d8962810" + "reference": "9e69c5eb5bdf79ff96c0396007f909e19fd8a956" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nutgram/nutgram/zipball/034257dbc29947b73e04b5d92b07d780d8962810", - "reference": "034257dbc29947b73e04b5d92b07d780d8962810", + "url": "https://api.github.com/repos/nutgram/nutgram/zipball/9e69c5eb5bdf79ff96c0396007f909e19fd8a956", + "reference": "9e69c5eb5bdf79ff96c0396007f909e19fd8a956", "shasum": "" }, "require": { @@ -1994,7 +1518,7 @@ ], "support": { "issues": "https://github.com/nutgram/nutgram/issues", - "source": "https://github.com/nutgram/nutgram/tree/4.42.0" + "source": "https://github.com/nutgram/nutgram/tree/4.44.0" }, "funding": [ { @@ -2006,7 +1530,7 @@ "type": "github" } ], - "time": "2026-02-12T17:23:52+00:00" + "time": "2026-03-02T00:33:48+00:00" }, { "name": "nyholm/psr7", @@ -2086,429 +1610,6 @@ ], "time": "2024-09-09T07:06:30+00:00" }, - { - "name": "opis/closure", - "version": "3.7.0", - "source": { - "type": "git", - "url": "https://github.com/opis/closure.git", - "reference": "b1a22a6be71c1263f3ca6e68f00b3fd4d394abc4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/opis/closure/zipball/b1a22a6be71c1263f3ca6e68f00b3fd4d394abc4", - "reference": "b1a22a6be71c1263f3ca6e68f00b3fd4d394abc4", - "shasum": "" - }, - "require": { - "php": "^5.4 || ^7.0 || ^8.0" - }, - "require-dev": { - "jeremeamia/superclosure": "^2.0", - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.6.x-dev" - } - }, - "autoload": { - "files": [ - "functions.php" - ], - "psr-4": { - "Opis\\Closure\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marius Sarca", - "email": "marius.sarca@gmail.com" - }, - { - "name": "Sorin Sarca", - "email": "sarca_sorin@hotmail.com" - } - ], - "description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.", - "homepage": "https://opis.io/closure", - "keywords": [ - "anonymous functions", - "closure", - "function", - "serializable", - "serialization", - "serialize" - ], - "support": { - "issues": "https://github.com/opis/closure/issues", - "source": "https://github.com/opis/closure/tree/3.7.0" - }, - "time": "2025-07-08T20:30:08+00:00" - }, - { - "name": "paragonie/random_compat", - "version": "v9.99.100", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", - "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", - "shasum": "" - }, - "require": { - "php": ">= 7" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*", - "vimeo/psalm": "^1" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" - } - ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", - "keywords": [ - "csprng", - "polyfill", - "pseudorandom", - "random" - ], - "support": { - "email": "info@paragonie.com", - "issues": "https://github.com/paragonie/random_compat/issues", - "source": "https://github.com/paragonie/random_compat" - }, - "time": "2020-10-15T08:29:30+00:00" - }, - { - "name": "php-di/invoker", - "version": "2.3.7", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/Invoker.git", - "reference": "3c1ddfdef181431fbc4be83378f6d036d59e81e1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/3c1ddfdef181431fbc4be83378f6d036d59e81e1", - "reference": "3c1ddfdef181431fbc4be83378f6d036d59e81e1", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "psr/container": "^1.0|^2.0" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "mnapoli/hard-mode": "~0.3.0", - "phpunit/phpunit": "^9.0 || ^10 || ^11 || ^12" - }, - "type": "library", - "autoload": { - "psr-4": { - "Invoker\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Generic and extensible callable invoker", - "homepage": "https://github.com/PHP-DI/Invoker", - "keywords": [ - "callable", - "dependency", - "dependency-injection", - "injection", - "invoke", - "invoker" - ], - "support": { - "issues": "https://github.com/PHP-DI/Invoker/issues", - "source": "https://github.com/PHP-DI/Invoker/tree/2.3.7" - }, - "funding": [ - { - "url": "https://github.com/mnapoli", - "type": "github" - } - ], - "time": "2025-08-30T10:22:22+00:00" - }, - { - "name": "php-di/php-di", - "version": "6.4.0", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/PHP-DI.git", - "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/ae0f1b3b03d8b29dff81747063cbfd6276246cc4", - "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4", - "shasum": "" - }, - "require": { - "laravel/serializable-closure": "^1.0", - "php": ">=7.4.0", - "php-di/invoker": "^2.0", - "php-di/phpdoc-reader": "^2.0.1", - "psr/container": "^1.0" - }, - "provide": { - "psr/container-implementation": "^1.0" - }, - "require-dev": { - "doctrine/annotations": "~1.10", - "friendsofphp/php-cs-fixer": "^2.4", - "mnapoli/phpunit-easymock": "^1.2", - "ocramius/proxy-manager": "^2.11.2", - "phpstan/phpstan": "^0.12", - "phpunit/phpunit": "^9.5" - }, - "suggest": { - "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", - "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~2.0)" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "DI\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "The dependency injection container for humans", - "homepage": "https://php-di.org/", - "keywords": [ - "PSR-11", - "container", - "container-interop", - "dependency injection", - "di", - "ioc", - "psr11" - ], - "support": { - "issues": "https://github.com/PHP-DI/PHP-DI/issues", - "source": "https://github.com/PHP-DI/PHP-DI/tree/6.4.0" - }, - "funding": [ - { - "url": "https://github.com/mnapoli", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", - "type": "tidelift" - } - ], - "time": "2022-04-09T16:46:38+00:00" - }, - { - "name": "php-di/phpdoc-reader", - "version": "2.2.1", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/PhpDocReader.git", - "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/66daff34cbd2627740ffec9469ffbac9f8c8185c", - "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c", - "shasum": "" - }, - "require": { - "php": ">=7.2.0" - }, - "require-dev": { - "mnapoli/hard-mode": "~0.3.0", - "phpunit/phpunit": "^8.5|^9.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "PhpDocReader\\": "src/PhpDocReader" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)", - "keywords": [ - "phpdoc", - "reflection" - ], - "support": { - "issues": "https://github.com/PHP-DI/PhpDocReader/issues", - "source": "https://github.com/PHP-DI/PhpDocReader/tree/2.2.1" - }, - "time": "2020-10-12T12:39:22+00:00" - }, - { - "name": "php-http/discovery", - "version": "1.20.0", - "source": { - "type": "git", - "url": "https://github.com/php-http/discovery.git", - "reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/discovery/zipball/82fe4c73ef3363caed49ff8dd1539ba06044910d", - "reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0|^2.0", - "php": "^7.1 || ^8.0" - }, - "conflict": { - "nyholm/psr7": "<1.0", - "zendframework/zend-diactoros": "*" - }, - "provide": { - "php-http/async-client-implementation": "*", - "php-http/client-implementation": "*", - "psr/http-client-implementation": "*", - "psr/http-factory-implementation": "*", - "psr/http-message-implementation": "*" - }, - "require-dev": { - "composer/composer": "^1.0.2|^2.0", - "graham-campbell/phpspec-skip-example-extension": "^5.0", - "php-http/httplug": "^1.0 || ^2.0", - "php-http/message-factory": "^1.0", - "phpspec/phpspec": "^5.1 || ^6.1 || ^7.3", - "sebastian/comparator": "^3.0.5 || ^4.0.8", - "symfony/phpunit-bridge": "^6.4.4 || ^7.0.1" - }, - "type": "composer-plugin", - "extra": { - "class": "Http\\Discovery\\Composer\\Plugin", - "plugin-optional": true - }, - "autoload": { - "psr-4": { - "Http\\Discovery\\": "src/" - }, - "exclude-from-classmap": [ - "src/Composer/Plugin.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - } - ], - "description": "Finds and installs PSR-7, PSR-17, PSR-18 and HTTPlug implementations", - "homepage": "http://php-http.org", - "keywords": [ - "adapter", - "client", - "discovery", - "factory", - "http", - "message", - "psr17", - "psr7" - ], - "support": { - "issues": "https://github.com/php-http/discovery/issues", - "source": "https://github.com/php-http/discovery/tree/1.20.0" - }, - "time": "2024-10-02T11:20:13+00:00" - }, - { - "name": "php-http/multipart-stream-builder", - "version": "1.4.2", - "source": { - "type": "git", - "url": "https://github.com/php-http/multipart-stream-builder.git", - "reference": "10086e6de6f53489cca5ecc45b6f468604d3460e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/multipart-stream-builder/zipball/10086e6de6f53489cca5ecc45b6f468604d3460e", - "reference": "10086e6de6f53489cca5ecc45b6f468604d3460e", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0", - "php-http/discovery": "^1.15", - "psr/http-factory-implementation": "^1.0" - }, - "require-dev": { - "nyholm/psr7": "^1.0", - "php-http/message": "^1.5", - "php-http/message-factory": "^1.0.2", - "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Http\\Message\\MultipartStream\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com" - } - ], - "description": "A builder class that help you create a multipart stream", - "homepage": "http://php-http.org", - "keywords": [ - "factory", - "http", - "message", - "multipart stream", - "stream" - ], - "support": { - "issues": "https://github.com/php-http/multipart-stream-builder/issues", - "source": "https://github.com/php-http/multipart-stream-builder/tree/1.4.2" - }, - "time": "2024-09-04T13:22:54+00:00" - }, { "name": "psr/cache", "version": "3.0.0", @@ -2608,22 +1709,27 @@ }, { "name": "psr/container", - "version": "1.1.2", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "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/" @@ -2650,9 +1756,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" + "source": "https://github.com/php-fig/container/tree/2.0.2" }, - "time": "2021-11-05T16:50:12+00:00" + "time": "2021-11-05T16:47:00+00:00" }, { "name": "psr/event-dispatcher", @@ -2813,16 +1919,16 @@ }, { "name": "psr/http-message", - "version": "1.1", + "version": "2.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", "shasum": "" }, "require": { @@ -2831,7 +1937,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -2846,7 +1952,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP messages", @@ -2860,36 +1966,36 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/1.1" + "source": "https://github.com/php-fig/http-message/tree/2.0" }, - "time": "2023-04-04T09:50:52+00:00" + "time": "2023-04-04T09:54:51+00:00" }, { "name": "psr/log", - "version": "1.1.4", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "3.x-dev" } }, "autoload": { "psr-4": { - "Psr\\Log\\": "Psr/Log/" + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -2910,9 +2016,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/1.1.4" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2021-05-03T11:20:27+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "psr/simple-cache", @@ -3009,902 +2115,6 @@ }, "time": "2019-03-08T08:55:37+00:00" }, - { - "name": "react/cache", - "version": "v1.2.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/cache.git", - "reference": "d47c472b64aa5608225f47965a484b75c7817d5b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b", - "reference": "d47c472b64aa5608225f47965a484b75c7817d5b", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "react/promise": "^3.0 || ^2.0 || ^1.1" - }, - "require-dev": { - "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\Cache\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "Async, Promise-based cache interface for ReactPHP", - "keywords": [ - "cache", - "caching", - "promise", - "reactphp" - ], - "support": { - "issues": "https://github.com/reactphp/cache/issues", - "source": "https://github.com/reactphp/cache/tree/v1.2.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2022-11-30T15:59:55+00:00" - }, - { - "name": "react/child-process", - "version": "v0.6.7", - "source": { - "type": "git", - "url": "https://github.com/reactphp/child-process.git", - "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/child-process/zipball/970f0e71945556422ee4570ccbabaedc3cf04ad3", - "reference": "970f0e71945556422ee4570ccbabaedc3cf04ad3", - "shasum": "" - }, - "require": { - "evenement/evenement": "^3.0 || ^2.0 || ^1.0", - "php": ">=5.3.0", - "react/event-loop": "^1.2", - "react/stream": "^1.4" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "react/socket": "^1.16", - "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\ChildProcess\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "Event-driven library for executing child processes with ReactPHP.", - "keywords": [ - "event-driven", - "process", - "reactphp" - ], - "support": { - "issues": "https://github.com/reactphp/child-process/issues", - "source": "https://github.com/reactphp/child-process/tree/v0.6.7" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2025-12-23T15:25:20+00:00" - }, - { - "name": "react/dns", - "version": "v1.14.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/dns.git", - "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/dns/zipball/7562c05391f42701c1fccf189c8225fece1cd7c3", - "reference": "7562c05391f42701c1fccf189c8225fece1cd7c3", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "react/cache": "^1.0 || ^0.6 || ^0.5", - "react/event-loop": "^1.2", - "react/promise": "^3.2 || ^2.7 || ^1.2.1" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "react/async": "^4.3 || ^3 || ^2", - "react/promise-timer": "^1.11" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\Dns\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "Async DNS resolver for ReactPHP", - "keywords": [ - "async", - "dns", - "dns-resolver", - "reactphp" - ], - "support": { - "issues": "https://github.com/reactphp/dns/issues", - "source": "https://github.com/reactphp/dns/tree/v1.14.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2025-11-18T19:34:28+00:00" - }, - { - "name": "react/event-loop", - "version": "v1.6.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/event-loop.git", - "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/event-loop/zipball/ba276bda6083df7e0050fd9b33f66ad7a4ac747a", - "reference": "ba276bda6083df7e0050fd9b33f66ad7a4ac747a", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" - }, - "suggest": { - "ext-pcntl": "For signal handling support when using the StreamSelectLoop" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\EventLoop\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", - "keywords": [ - "asynchronous", - "event-loop" - ], - "support": { - "issues": "https://github.com/reactphp/event-loop/issues", - "source": "https://github.com/reactphp/event-loop/tree/v1.6.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2025-11-17T20:46:25+00:00" - }, - { - "name": "react/filesystem", - "version": "v0.1.2", - "source": { - "type": "git", - "url": "https://github.com/reactphp/filesystem.git", - "reference": "766cdef9ba806367114f0c5ba36ea2a6eec8ccd2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/filesystem/zipball/766cdef9ba806367114f0c5ba36ea2a6eec8ccd2", - "reference": "766cdef9ba806367114f0c5ba36ea2a6eec8ccd2", - "shasum": "" - }, - "require": { - "evenement/evenement": "^3.0 || ^2.0", - "php": ">=5.4.0", - "react/event-loop": "^1.0 || ^0.5 || ^0.4", - "react/promise": "~2.2", - "react/promise-stream": "^1.1", - "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4", - "wyrihaximus/react-child-process-pool": "^1.3" - }, - "require-dev": { - "clue/block-react": "^1.1", - "phpunit/phpunit": "^6.0 || ^5.0 || ^4.8" - }, - "suggest": { - "ext-eio": "^1.2" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "React\\Filesystem\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com" - } - ], - "description": "Asynchronous filesystem abstraction.", - "keywords": [ - "asynchronous", - "eio", - "filesystem" - ], - "support": { - "issues": "https://github.com/reactphp/filesystem/issues", - "source": "https://github.com/reactphp/filesystem/tree/master" - }, - "time": "2018-10-22T12:10:29+00:00" - }, - { - "name": "react/http", - "version": "v1.11.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/http.git", - "reference": "8db02de41dcca82037367f67a2d4be365b1c4db9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/http/zipball/8db02de41dcca82037367f67a2d4be365b1c4db9", - "reference": "8db02de41dcca82037367f67a2d4be365b1c4db9", - "shasum": "" - }, - "require": { - "evenement/evenement": "^3.0 || ^2.0 || ^1.0", - "fig/http-message-util": "^1.1", - "php": ">=5.3.0", - "psr/http-message": "^1.0", - "react/event-loop": "^1.2", - "react/promise": "^3.2 || ^2.3 || ^1.2.1", - "react/socket": "^1.16", - "react/stream": "^1.4" - }, - "require-dev": { - "clue/http-proxy-react": "^1.8", - "clue/reactphp-ssh-proxy": "^1.4", - "clue/socks-react": "^1.4", - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "react/async": "^4.2 || ^3 || ^2", - "react/promise-stream": "^1.4", - "react/promise-timer": "^1.11" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\Http\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "Event-driven, streaming HTTP client and server implementation for ReactPHP", - "keywords": [ - "async", - "client", - "event-driven", - "http", - "http client", - "http server", - "https", - "psr-7", - "reactphp", - "server", - "streaming" - ], - "support": { - "issues": "https://github.com/reactphp/http/issues", - "source": "https://github.com/reactphp/http/tree/v1.11.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2024-11-20T15:24:08+00:00" - }, - { - "name": "react/promise", - "version": "v2.11.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/promise.git", - "reference": "1a8460931ea36dc5c76838fec5734d55c88c6831" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/1a8460931ea36dc5c76838fec5734d55c88c6831", - "reference": "1a8460931ea36dc5c76838fec5734d55c88c6831", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "React\\Promise\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "A lightweight implementation of CommonJS Promises/A for PHP", - "keywords": [ - "promise", - "promises" - ], - "support": { - "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v2.11.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2023-11-16T16:16:50+00:00" - }, - { - "name": "react/promise-stream", - "version": "v1.7.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/promise-stream.git", - "reference": "5c7ec3450f558deb779742e33967d837e2db7871" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise-stream/zipball/5c7ec3450f558deb779742e33967d837e2db7871", - "reference": "5c7ec3450f558deb779742e33967d837e2db7871", - "shasum": "" - }, - "require": { - "php": ">=5.3", - "react/promise": "^3 || ^2.1 || ^1.2", - "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4.6" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "React\\Promise\\Stream\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "The missing link between Promise-land and Stream-land for ReactPHP", - "homepage": "https://github.com/reactphp/promise-stream", - "keywords": [ - "Buffer", - "async", - "promise", - "reactphp", - "stream", - "unwrap" - ], - "support": { - "issues": "https://github.com/reactphp/promise-stream/issues", - "source": "https://github.com/reactphp/promise-stream/tree/v1.7.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2023-12-13T11:32:02+00:00" - }, - { - "name": "react/promise-timer", - "version": "v1.11.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/promise-timer.git", - "reference": "4f70306ed66b8b44768941ca7f142092600fafc1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise-timer/zipball/4f70306ed66b8b44768941ca7f142092600fafc1", - "reference": "4f70306ed66b8b44768941ca7f142092600fafc1", - "shasum": "" - }, - "require": { - "php": ">=5.3", - "react/event-loop": "^1.2", - "react/promise": "^3.2 || ^2.7.0 || ^1.2.1" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "React\\Promise\\Timer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "A trivial implementation of timeouts for Promises, built on top of ReactPHP.", - "homepage": "https://github.com/reactphp/promise-timer", - "keywords": [ - "async", - "event-loop", - "promise", - "reactphp", - "timeout", - "timer" - ], - "support": { - "issues": "https://github.com/reactphp/promise-timer/issues", - "source": "https://github.com/reactphp/promise-timer/tree/v1.11.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2024-06-04T14:27:45+00:00" - }, - { - "name": "react/socket", - "version": "v1.17.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/socket.git", - "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/socket/zipball/ef5b17b81f6f60504c539313f94f2d826c5faa08", - "reference": "ef5b17b81f6f60504c539313f94f2d826c5faa08", - "shasum": "" - }, - "require": { - "evenement/evenement": "^3.0 || ^2.0 || ^1.0", - "php": ">=5.3.0", - "react/dns": "^1.13", - "react/event-loop": "^1.2", - "react/promise": "^3.2 || ^2.6 || ^1.2.1", - "react/stream": "^1.4" - }, - "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "react/async": "^4.3 || ^3.3 || ^2", - "react/promise-stream": "^1.4", - "react/promise-timer": "^1.11" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\Socket\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", - "keywords": [ - "Connection", - "Socket", - "async", - "reactphp", - "stream" - ], - "support": { - "issues": "https://github.com/reactphp/socket/issues", - "source": "https://github.com/reactphp/socket/tree/v1.17.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2025-11-19T20:47:34+00:00" - }, - { - "name": "react/stream", - "version": "v1.4.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/stream.git", - "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", - "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", - "shasum": "" - }, - "require": { - "evenement/evenement": "^3.0 || ^2.0 || ^1.0", - "php": ">=5.3.8", - "react/event-loop": "^1.2" - }, - "require-dev": { - "clue/stream-filter": "~1.2", - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" - }, - "type": "library", - "autoload": { - "psr-4": { - "React\\Stream\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Lück", - "email": "christian@clue.engineering", - "homepage": "https://clue.engineering/" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "reactphp@ceesjankiewiet.nl", - "homepage": "https://wyrihaximus.net/" - }, - { - "name": "Jan Sorgalla", - "email": "jsorgalla@gmail.com", - "homepage": "https://sorgalla.com/" - }, - { - "name": "Chris Boden", - "email": "cboden@gmail.com", - "homepage": "https://cboden.dev/" - } - ], - "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", - "keywords": [ - "event-driven", - "io", - "non-blocking", - "pipe", - "reactphp", - "readable", - "stream", - "writable" - ], - "support": { - "issues": "https://github.com/reactphp/stream/issues", - "source": "https://github.com/reactphp/stream/tree/v1.4.0" - }, - "funding": [ - { - "url": "https://opencollective.com/reactphp", - "type": "open_collective" - } - ], - "time": "2024-06-11T12:45:25+00:00" - }, - { - "name": "ringcentral/psr7", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/ringcentral/psr7.git", - "reference": "360faaec4b563958b673fb52bbe94e37f14bc686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ringcentral/psr7/zipball/360faaec4b563958b673fb52bbe94e37f14bc686", - "reference": "360faaec4b563958b673fb52bbe94e37f14bc686", - "shasum": "" - }, - "require": { - "php": ">=5.3", - "psr/http-message": "~1.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "RingCentral\\Psr7\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "PSR-7 message implementation", - "keywords": [ - "http", - "message", - "stream", - "uri" - ], - "support": { - "source": "https://github.com/ringcentral/psr7/tree/master" - }, - "time": "2018-05-29T20:21:04+00:00" - }, { "name": "sergix44/container", "version": "3.1.0", @@ -3996,16 +2206,16 @@ }, { "name": "symfony/cache", - "version": "v8.0.5", + "version": "v8.0.7", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "92e9960386c7e01f58198038c199d522959a843c" + "reference": "b7b0f4ce5fb57a8dc061d494639e44e2cf7aa30f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/92e9960386c7e01f58198038c199d522959a843c", - "reference": "92e9960386c7e01f58198038c199d522959a843c", + "url": "https://api.github.com/repos/symfony/cache/zipball/b7b0f4ce5fb57a8dc061d494639e44e2cf7aa30f", + "reference": "b7b0f4ce5fb57a8dc061d494639e44e2cf7aa30f", "shasum": "" }, "require": { @@ -4072,7 +2282,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v8.0.5" + "source": "https://github.com/symfony/cache/tree/v8.0.7" }, "funding": [ { @@ -4092,7 +2302,7 @@ "type": "tidelift" } ], - "time": "2026-01-27T16:18:07+00:00" + "time": "2026-03-06T13:17:40+00:00" }, { "name": "symfony/cache-contracts", @@ -4247,165 +2457,6 @@ ], "time": "2025-11-12T15:46:48+00:00" }, - { - "name": "symfony/config", - "version": "v8.0.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "8f45af92f08f82902827a8b6f403aaf49d893539" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/8f45af92f08f82902827a8b6f403aaf49d893539", - "reference": "8f45af92f08f82902827a8b6f403aaf49d893539", - "shasum": "" - }, - "require": { - "php": ">=8.4", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^7.4|^8.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "symfony/service-contracts": "<2.5" - }, - "require-dev": { - "symfony/event-dispatcher": "^7.4|^8.0", - "symfony/finder": "^7.4|^8.0", - "symfony/messenger": "^7.4|^8.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^7.4|^8.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/v8.0.4" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-13T13:06:50+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v8.0.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "40a6c455ade7e3bf25900d6b746d40cfa2573e26" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/40a6c455ade7e3bf25900d6b746d40cfa2573e26", - "reference": "40a6c455ade7e3bf25900d6b746d40cfa2573e26", - "shasum": "" - }, - "require": { - "php": ">=8.4", - "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/service-contracts": "^3.6", - "symfony/var-exporter": "^7.4|^8.0" - }, - "conflict": { - "ext-psr": "<1.1|>=2" - }, - "provide": { - "psr/container-implementation": "1.1|2.0", - "symfony/service-implementation": "1.1|2.0|3.0" - }, - "require-dev": { - "symfony/config": "^7.4|^8.0", - "symfony/expression-language": "^7.4|^8.0", - "symfony/yaml": "^7.4|^8.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/v8.0.5" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-27T16:18:07+00:00" - }, { "name": "symfony/deprecation-contracts", "version": "v3.6.0", @@ -4473,882 +2524,6 @@ ], "time": "2024-09-25T14:21:43+00:00" }, - { - "name": "symfony/error-handler", - "version": "v8.0.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/error-handler.git", - "reference": "7620b97ec0ab1d2d6c7fb737aa55da411bea776a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/7620b97ec0ab1d2d6c7fb737aa55da411bea776a", - "reference": "7620b97ec0ab1d2d6c7fb737aa55da411bea776a", - "shasum": "" - }, - "require": { - "php": ">=8.4", - "psr/log": "^1|^2|^3", - "symfony/polyfill-php85": "^1.32", - "symfony/var-dumper": "^7.4|^8.0" - }, - "conflict": { - "symfony/deprecation-contracts": "<2.5" - }, - "require-dev": { - "symfony/console": "^7.4|^8.0", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-kernel": "^7.4|^8.0", - "symfony/serializer": "^7.4|^8.0", - "symfony/webpack-encore-bundle": "^1.0|^2.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/v8.0.4" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-23T11:07:10+00:00" - }, - { - "name": "symfony/event-dispatcher", - "version": "v8.0.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "99301401da182b6cfaa4700dbe9987bb75474b47" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/99301401da182b6cfaa4700dbe9987bb75474b47", - "reference": "99301401da182b6cfaa4700dbe9987bb75474b47", - "shasum": "" - }, - "require": { - "php": ">=8.4", - "symfony/event-dispatcher-contracts": "^2.5|^3" - }, - "conflict": { - "symfony/security-http": "<7.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": "^7.4|^8.0", - "symfony/dependency-injection": "^7.4|^8.0", - "symfony/error-handler": "^7.4|^8.0", - "symfony/expression-language": "^7.4|^8.0", - "symfony/framework-bundle": "^7.4|^8.0", - "symfony/http-foundation": "^7.4|^8.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^7.4|^8.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/v8.0.4" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-05T11:45:55+00:00" - }, - { - "name": "symfony/event-dispatcher-contracts", - "version": "v3.6.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/event-dispatcher": "^1" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } - }, - "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.6.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": "2024-09-25T14:21:43+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v8.0.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "d937d400b980523dc9ee946bb69972b5e619058d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d", - "reference": "d937d400b980523dc9ee946bb69972b5e619058d", - "shasum": "" - }, - "require": { - "php": ">=8.4", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8" - }, - "require-dev": { - "symfony/process": "^7.4|^8.0" - }, - "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/v8.0.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-12-01T09:13:36+00:00" - }, - { - "name": "symfony/finder", - "version": "v8.0.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/8bd576e97c67d45941365bf824e18dc8538e6eb0", - "reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0", - "shasum": "" - }, - "require": { - "php": ">=8.4" - }, - "require-dev": { - "symfony/filesystem": "^7.4|^8.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/v8.0.5" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-26T15:08:38+00:00" - }, - { - "name": "symfony/framework-bundle", - "version": "v8.0.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/framework-bundle.git", - "reference": "e2f9469e7a802dd7c0d193792afc494d68177c54" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/e2f9469e7a802dd7c0d193792afc494d68177c54", - "reference": "e2f9469e7a802dd7c0d193792afc494d68177c54", - "shasum": "" - }, - "require": { - "composer-runtime-api": ">=2.1", - "ext-xml": "*", - "php": ">=8.4", - "symfony/cache": "^7.4|^8.0", - "symfony/config": "^7.4.4|^8.0.4", - "symfony/dependency-injection": "^7.4.4|^8.0.4", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^7.4|^8.0", - "symfony/event-dispatcher": "^7.4|^8.0", - "symfony/filesystem": "^7.4|^8.0", - "symfony/finder": "^7.4|^8.0", - "symfony/http-foundation": "^7.4|^8.0", - "symfony/http-kernel": "^7.4|^8.0", - "symfony/polyfill-mbstring": "^1.0", - "symfony/polyfill-php85": "^1.32", - "symfony/routing": "^7.4|^8.0" - }, - "conflict": { - "doctrine/persistence": "<1.3", - "phpdocumentor/reflection-docblock": "<5.2|>=6", - "phpdocumentor/type-resolver": "<1.5.1", - "symfony/console": "<7.4", - "symfony/form": "<7.4", - "symfony/json-streamer": "<7.4", - "symfony/messenger": "<7.4", - "symfony/security-csrf": "<7.4", - "symfony/serializer": "<7.4", - "symfony/translation": "<7.4", - "symfony/webhook": "<7.4", - "symfony/workflow": "<7.4" - }, - "require-dev": { - "doctrine/persistence": "^1.3|^2|^3", - "dragonmantank/cron-expression": "^3.1", - "phpdocumentor/reflection-docblock": "^5.2", - "phpstan/phpdoc-parser": "^1.0|^2.0", - "seld/jsonlint": "^1.10", - "symfony/asset": "^7.4|^8.0", - "symfony/asset-mapper": "^7.4|^8.0", - "symfony/browser-kit": "^7.4|^8.0", - "symfony/clock": "^7.4|^8.0", - "symfony/console": "^7.4|^8.0", - "symfony/css-selector": "^7.4|^8.0", - "symfony/dom-crawler": "^7.4|^8.0", - "symfony/dotenv": "^7.4|^8.0", - "symfony/expression-language": "^7.4|^8.0", - "symfony/form": "^7.4|^8.0", - "symfony/html-sanitizer": "^7.4|^8.0", - "symfony/http-client": "^7.4|^8.0", - "symfony/json-streamer": "^7.4|^8.0", - "symfony/lock": "^7.4|^8.0", - "symfony/mailer": "^7.4|^8.0", - "symfony/messenger": "^7.4|^8.0", - "symfony/mime": "^7.4|^8.0", - "symfony/notifier": "^7.4|^8.0", - "symfony/object-mapper": "^7.4|^8.0", - "symfony/polyfill-intl-icu": "^1.0", - "symfony/process": "^7.4|^8.0", - "symfony/property-info": "^7.4|^8.0", - "symfony/rate-limiter": "^7.4|^8.0", - "symfony/runtime": "^7.4|^8.0", - "symfony/scheduler": "^7.4|^8.0", - "symfony/security-bundle": "^7.4|^8.0", - "symfony/semaphore": "^7.4|^8.0", - "symfony/serializer": "^7.4|^8.0", - "symfony/stopwatch": "^7.4|^8.0", - "symfony/string": "^7.4|^8.0", - "symfony/translation": "^7.4|^8.0", - "symfony/twig-bundle": "^7.4|^8.0", - "symfony/type-info": "^7.4.1|^8.0.1", - "symfony/uid": "^7.4|^8.0", - "symfony/validator": "^7.4|^8.0", - "symfony/web-link": "^7.4|^8.0", - "symfony/webhook": "^7.4|^8.0", - "symfony/workflow": "^7.4|^8.0", - "symfony/yaml": "^7.4|^8.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/v8.0.5" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-27T09:06:10+00:00" - }, - { - "name": "symfony/http-foundation", - "version": "v8.0.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "e3422806e6f6760dbed0ddbc0a7fbfb6b5ce96bb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e3422806e6f6760dbed0ddbc0a7fbfb6b5ce96bb", - "reference": "e3422806e6f6760dbed0ddbc0a7fbfb6b5ce96bb", - "shasum": "" - }, - "require": { - "php": ">=8.4", - "symfony/polyfill-mbstring": "^1.1" - }, - "conflict": { - "doctrine/dbal": "<4.3" - }, - "require-dev": { - "doctrine/dbal": "^4.3", - "predis/predis": "^1.1|^2.0", - "symfony/cache": "^7.4|^8.0", - "symfony/clock": "^7.4|^8.0", - "symfony/dependency-injection": "^7.4|^8.0", - "symfony/expression-language": "^7.4|^8.0", - "symfony/http-kernel": "^7.4|^8.0", - "symfony/mime": "^7.4|^8.0", - "symfony/rate-limiter": "^7.4|^8.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/v8.0.5" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-27T16:18:07+00:00" - }, - { - "name": "symfony/http-kernel", - "version": "v8.0.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-kernel.git", - "reference": "20c1c5e41fc53928dbb670088f544f2d460d497d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/20c1c5e41fc53928dbb670088f544f2d460d497d", - "reference": "20c1c5e41fc53928dbb670088f544f2d460d497d", - "shasum": "" - }, - "require": { - "php": ">=8.4", - "psr/log": "^1|^2|^3", - "symfony/error-handler": "^7.4|^8.0", - "symfony/event-dispatcher": "^7.4|^8.0", - "symfony/http-foundation": "^7.4|^8.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "symfony/flex": "<2.10", - "symfony/http-client-contracts": "<2.5", - "symfony/translation-contracts": "<2.5", - "twig/twig": "<3.21" - }, - "provide": { - "psr/log-implementation": "1.0|2.0|3.0" - }, - "require-dev": { - "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^7.4|^8.0", - "symfony/clock": "^7.4|^8.0", - "symfony/config": "^7.4|^8.0", - "symfony/console": "^7.4|^8.0", - "symfony/css-selector": "^7.4|^8.0", - "symfony/dependency-injection": "^7.4|^8.0", - "symfony/dom-crawler": "^7.4|^8.0", - "symfony/expression-language": "^7.4|^8.0", - "symfony/finder": "^7.4|^8.0", - "symfony/http-client-contracts": "^2.5|^3", - "symfony/process": "^7.4|^8.0", - "symfony/property-access": "^7.4|^8.0", - "symfony/routing": "^7.4|^8.0", - "symfony/serializer": "^7.4|^8.0", - "symfony/stopwatch": "^7.4|^8.0", - "symfony/translation": "^7.4|^8.0", - "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^7.4|^8.0", - "symfony/validator": "^7.4|^8.0", - "symfony/var-dumper": "^7.4|^8.0", - "symfony/var-exporter": "^7.4|^8.0", - "twig/twig": "^3.21" - }, - "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/v8.0.5" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-28T10:46:31+00:00" - }, - { - "name": "symfony/intl", - "version": "v8.0.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/intl.git", - "reference": "8d049269c2accca0b02e5f9de39f3ee92ebc4468" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/8d049269c2accca0b02e5f9de39f3ee92ebc4468", - "reference": "8d049269c2accca0b02e5f9de39f3ee92ebc4468", - "shasum": "" - }, - "require": { - "php": ">=8.4" - }, - "conflict": { - "symfony/string": "<7.4" - }, - "require-dev": { - "symfony/filesystem": "^7.4|^8.0", - "symfony/var-exporter": "^7.4|^8.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Intl\\": "" - }, - "exclude-from-classmap": [ - "/Tests/", - "/Resources/data/" - ] - }, - "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/v8.0.4" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-12T12:37:40+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-09T11:45:10+00:00" - }, { "name": "symfony/polyfill-mbstring", "version": "v1.33.0", @@ -5674,86 +2849,6 @@ ], "time": "2025-06-23T16:12:55+00:00" }, - { - "name": "symfony/routing", - "version": "v8.0.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/routing.git", - "reference": "4a2bc08d1c35307239329f434d45c2bfe8241fa9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/4a2bc08d1c35307239329f434d45c2bfe8241fa9", - "reference": "4a2bc08d1c35307239329f434d45c2bfe8241fa9", - "shasum": "" - }, - "require": { - "php": ">=8.4", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "require-dev": { - "psr/log": "^1|^2|^3", - "symfony/config": "^7.4|^8.0", - "symfony/dependency-injection": "^7.4|^8.0", - "symfony/expression-language": "^7.4|^8.0", - "symfony/http-foundation": "^7.4|^8.0", - "symfony/yaml": "^7.4|^8.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/v8.0.4" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-12T12:37:40+00:00" - }, { "name": "symfony/service-contracts", "version": "v3.6.1", @@ -5843,16 +2938,16 @@ }, { "name": "symfony/translation", - "version": "v8.0.4", + "version": "v8.0.6", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "db70c8ce7db74fd2da7b1d268db46b2a8ce32c10" + "reference": "13ff19bcf2bea492d3c2fbeaa194dd6f4599ce1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/db70c8ce7db74fd2da7b1d268db46b2a8ce32c10", - "reference": "db70c8ce7db74fd2da7b1d268db46b2a8ce32c10", + "url": "https://api.github.com/repos/symfony/translation/zipball/13ff19bcf2bea492d3c2fbeaa194dd6f4599ce1b", + "reference": "13ff19bcf2bea492d3c2fbeaa194dd6f4599ce1b", "shasum": "" }, "require": { @@ -5912,7 +3007,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v8.0.4" + "source": "https://github.com/symfony/translation/tree/v8.0.6" }, "funding": [ { @@ -5932,7 +3027,7 @@ "type": "tidelift" } ], - "time": "2026-01-13T13:06:50+00:00" + "time": "2026-02-17T13:07:04+00:00" }, { "name": "symfony/translation-contracts", @@ -6016,284 +3111,6 @@ ], "time": "2025-07-15T13:41:35+00:00" }, - { - "name": "symfony/twig-bridge", - "version": "v8.0.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/twig-bridge.git", - "reference": "3e60c35cb47b1077524c066ec277eaf92cdc2393" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/3e60c35cb47b1077524c066ec277eaf92cdc2393", - "reference": "3e60c35cb47b1077524c066ec277eaf92cdc2393", - "shasum": "" - }, - "require": { - "php": ">=8.4", - "symfony/translation-contracts": "^2.5|^3", - "twig/twig": "^3.21" - }, - "conflict": { - "phpdocumentor/reflection-docblock": "<5.2|>=6", - "phpdocumentor/type-resolver": "<1.5.1", - "symfony/form": "<7.4.4|>8.0,<8.0.4" - }, - "require-dev": { - "egulias/email-validator": "^2.1.10|^3|^4", - "league/html-to-markdown": "^5.0", - "phpdocumentor/reflection-docblock": "^5.2", - "symfony/asset": "^7.4|^8.0", - "symfony/asset-mapper": "^7.4|^8.0", - "symfony/console": "^7.4|^8.0", - "symfony/dependency-injection": "^7.4|^8.0", - "symfony/emoji": "^7.4|^8.0", - "symfony/expression-language": "^7.4|^8.0", - "symfony/finder": "^7.4|^8.0", - "symfony/form": "^7.4.4|^8.0.4", - "symfony/html-sanitizer": "^7.4|^8.0", - "symfony/http-foundation": "^7.4|^8.0", - "symfony/http-kernel": "^7.4|^8.0", - "symfony/intl": "^7.4|^8.0", - "symfony/mime": "^7.4|^8.0", - "symfony/polyfill-intl-icu": "^1.0", - "symfony/property-info": "^7.4|^8.0", - "symfony/routing": "^7.4|^8.0", - "symfony/security-acl": "^2.8|^3.0", - "symfony/security-core": "^7.4|^8.0", - "symfony/security-csrf": "^7.4|^8.0", - "symfony/security-http": "^7.4|^8.0", - "symfony/serializer": "^7.4|^8.0", - "symfony/stopwatch": "^7.4|^8.0", - "symfony/translation": "^7.4|^8.0", - "symfony/validator": "^7.4|^8.0", - "symfony/web-link": "^7.4|^8.0", - "symfony/workflow": "^7.4|^8.0", - "symfony/yaml": "^7.4|^8.0", - "twig/cssinliner-extra": "^3", - "twig/inky-extra": "^3", - "twig/markdown-extra": "^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/v8.0.5" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-27T09:06:10+00:00" - }, - { - "name": "symfony/twig-bundle", - "version": "v8.0.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/twig-bundle.git", - "reference": "5a68f2e0e06996514bf04900c3982b93b42487af" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/5a68f2e0e06996514bf04900c3982b93b42487af", - "reference": "5a68f2e0e06996514bf04900c3982b93b42487af", - "shasum": "" - }, - "require": { - "composer-runtime-api": ">=2.1", - "php": ">=8.4", - "symfony/config": "^7.4|^8.0", - "symfony/dependency-injection": "^7.4|^8.0", - "symfony/http-foundation": "^7.4|^8.0", - "symfony/http-kernel": "^7.4|^8.0", - "symfony/twig-bridge": "^7.4|^8.0" - }, - "require-dev": { - "symfony/asset": "^7.4|^8.0", - "symfony/expression-language": "^7.4|^8.0", - "symfony/finder": "^7.4|^8.0", - "symfony/form": "^7.4|^8.0", - "symfony/framework-bundle": "^7.4|^8.0", - "symfony/routing": "^7.4|^8.0", - "symfony/runtime": "^7.4|^8.0", - "symfony/stopwatch": "^7.4|^8.0", - "symfony/translation": "^7.4|^8.0", - "symfony/web-link": "^7.4|^8.0", - "symfony/yaml": "^7.4|^8.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/v8.0.4" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-06T12:43:21+00:00" - }, - { - "name": "symfony/var-dumper", - "version": "v8.0.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "326e0406fc315eca57ef5740fa4a280b7a068c82" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/326e0406fc315eca57ef5740fa4a280b7a068c82", - "reference": "326e0406fc315eca57ef5740fa4a280b7a068c82", - "shasum": "" - }, - "require": { - "php": ">=8.4", - "symfony/polyfill-mbstring": "^1.0" - }, - "conflict": { - "symfony/console": "<7.4", - "symfony/error-handler": "<7.4" - }, - "require-dev": { - "symfony/console": "^7.4|^8.0", - "symfony/http-kernel": "^7.4|^8.0", - "symfony/process": "^7.4|^8.0", - "symfony/uid": "^7.4|^8.0", - "twig/twig": "^3.12" - }, - "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/v8.0.4" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-01T23:07:29+00:00" - }, { "name": "symfony/var-exporter", "version": "v8.0.0", @@ -6374,414 +3191,6 @@ ], "time": "2025-11-05T18:53:00+00:00" }, - { - "name": "thecodingmachine/safe", - "version": "v2.5.0", - "source": { - "type": "git", - "url": "https://github.com/thecodingmachine/safe.git", - "reference": "3115ecd6b4391662b4931daac4eba6b07a2ac1f0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/3115ecd6b4391662b4931daac4eba6b07a2ac1f0", - "reference": "3115ecd6b4391662b4931daac4eba6b07a2ac1f0", - "shasum": "" - }, - "require": { - "php": "^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.5", - "phpunit/phpunit": "^9.5", - "squizlabs/php_codesniffer": "^3.2", - "thecodingmachine/phpstan-strict-rules": "^1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.2.x-dev" - } - }, - "autoload": { - "files": [ - "deprecated/apc.php", - "deprecated/array.php", - "deprecated/datetime.php", - "deprecated/libevent.php", - "deprecated/misc.php", - "deprecated/password.php", - "deprecated/mssql.php", - "deprecated/stats.php", - "deprecated/strings.php", - "lib/special_cases.php", - "deprecated/mysqli.php", - "generated/apache.php", - "generated/apcu.php", - "generated/array.php", - "generated/bzip2.php", - "generated/calendar.php", - "generated/classobj.php", - "generated/com.php", - "generated/cubrid.php", - "generated/curl.php", - "generated/datetime.php", - "generated/dir.php", - "generated/eio.php", - "generated/errorfunc.php", - "generated/exec.php", - "generated/fileinfo.php", - "generated/filesystem.php", - "generated/filter.php", - "generated/fpm.php", - "generated/ftp.php", - "generated/funchand.php", - "generated/gettext.php", - "generated/gmp.php", - "generated/gnupg.php", - "generated/hash.php", - "generated/ibase.php", - "generated/ibmDb2.php", - "generated/iconv.php", - "generated/image.php", - "generated/imap.php", - "generated/info.php", - "generated/inotify.php", - "generated/json.php", - "generated/ldap.php", - "generated/libxml.php", - "generated/lzf.php", - "generated/mailparse.php", - "generated/mbstring.php", - "generated/misc.php", - "generated/mysql.php", - "generated/network.php", - "generated/oci8.php", - "generated/opcache.php", - "generated/openssl.php", - "generated/outcontrol.php", - "generated/pcntl.php", - "generated/pcre.php", - "generated/pgsql.php", - "generated/posix.php", - "generated/ps.php", - "generated/pspell.php", - "generated/readline.php", - "generated/rpminfo.php", - "generated/rrd.php", - "generated/sem.php", - "generated/session.php", - "generated/shmop.php", - "generated/sockets.php", - "generated/sodium.php", - "generated/solr.php", - "generated/spl.php", - "generated/sqlsrv.php", - "generated/ssdeep.php", - "generated/ssh2.php", - "generated/stream.php", - "generated/strings.php", - "generated/swoole.php", - "generated/uodbc.php", - "generated/uopz.php", - "generated/url.php", - "generated/var.php", - "generated/xdiff.php", - "generated/xml.php", - "generated/xmlrpc.php", - "generated/yaml.php", - "generated/yaz.php", - "generated/zip.php", - "generated/zlib.php" - ], - "classmap": [ - "lib/DateTime.php", - "lib/DateTimeImmutable.php", - "lib/Exceptions/", - "deprecated/Exceptions/", - "generated/Exceptions/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHP core functions that throw exceptions instead of returning FALSE on error", - "support": { - "issues": "https://github.com/thecodingmachine/safe/issues", - "source": "https://github.com/thecodingmachine/safe/tree/v2.5.0" - }, - "time": "2023-04-05T11:54:14+00:00" - }, - { - "name": "tivie/php-os-detector", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/tivie/php-os-detector.git", - "reference": "9461dcd85c00e03842264f2fc8ccdc8d46867321" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/tivie/php-os-detector/zipball/9461dcd85c00e03842264f2fc8ccdc8d46867321", - "reference": "9461dcd85c00e03842264f2fc8ccdc8d46867321", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "4.3.*" - }, - "type": "library", - "autoload": { - "psr-4": { - "Tivie\\OS\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "APACHE 2.0" - ], - "authors": [ - { - "name": "Estevão Soares dos Santos", - "email": "estevao@soares-dos-santos.com" - } - ], - "description": "A small utility library that detects the OS the server is running on", - "homepage": "http://tivie.github.com/php-os-detector/", - "keywords": [ - "detection", - "detector", - "identification", - "operating system", - "os", - "os detection" - ], - "support": { - "issues": "https://github.com/tivie/php-os-detector/issues", - "source": "https://github.com/tivie/php-os-detector/tree/master" - }, - "time": "2017-10-21T03:33:59+00:00" - }, - { - "name": "twig/extra-bundle", - "version": "v3.23.0", - "source": { - "type": "git", - "url": "https://github.com/twigphp/twig-extra-bundle.git", - "reference": "7a27e784dc56eddfef5e9295829b290ce06f1682" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/7a27e784dc56eddfef5e9295829b290ce06f1682", - "reference": "7a27e784dc56eddfef5e9295829b290ce06f1682", - "shasum": "" - }, - "require": { - "php": ">=8.1.0", - "symfony/framework-bundle": "^5.4|^6.4|^7.0|^8.0", - "symfony/twig-bundle": "^5.4|^6.4|^7.0|^8.0", - "twig/twig": "^3.2|^4.0" - }, - "require-dev": { - "league/commonmark": "^2.7", - "symfony/phpunit-bridge": "^6.4|^7.0", - "twig/cache-extra": "^3.0", - "twig/cssinliner-extra": "^3.0", - "twig/html-extra": "^3.0", - "twig/inky-extra": "^3.0", - "twig/intl-extra": "^3.0", - "twig/markdown-extra": "^3.0", - "twig/string-extra": "^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.23.0" - }, - "funding": [ - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/twig/twig", - "type": "tidelift" - } - ], - "time": "2025-12-18T20:46:15+00:00" - }, - { - "name": "twig/intl-extra", - "version": "v3.23.0", - "source": { - "type": "git", - "url": "https://github.com/twigphp/intl-extra.git", - "reference": "32f15a38d45a8d0ec11bc8a3d97d3ac2a261499f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/32f15a38d45a8d0ec11bc8a3d97d3ac2a261499f", - "reference": "32f15a38d45a8d0ec11bc8a3d97d3ac2a261499f", - "shasum": "" - }, - "require": { - "php": ">=8.1.0", - "symfony/intl": "^5.4|^6.4|^7.0|^8.0", - "twig/twig": "^3.13|^4.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Twig\\Extra\\Intl\\": "" - }, - "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 Twig extension for Intl", - "homepage": "https://twig.symfony.com", - "keywords": [ - "intl", - "twig" - ], - "support": { - "source": "https://github.com/twigphp/intl-extra/tree/v3.23.0" - }, - "funding": [ - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/twig/twig", - "type": "tidelift" - } - ], - "time": "2026-01-17T13:57:47+00:00" - }, - { - "name": "twig/twig", - "version": "v3.23.0", - "source": { - "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9", - "reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9", - "shasum": "" - }, - "require": { - "php": ">=8.1.0", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-mbstring": "^1.3" - }, - "require-dev": { - "phpstan/phpstan": "^2.0", - "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" - }, - "type": "library", - "autoload": { - "files": [ - "src/Resources/core.php", - "src/Resources/debug.php", - "src/Resources/escaper.php", - "src/Resources/string_loader.php" - ], - "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.23.0" - }, - "funding": [ - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/twig/twig", - "type": "tidelift" - } - ], - "time": "2026-01-23T21:00:41+00:00" - }, { "name": "voku/portable-ascii", "version": "2.0.3", @@ -6855,583 +3264,6 @@ } ], "time": "2024-11-21T01:49:47+00:00" - }, - { - "name": "wyrihaximus/composer-update-bin-autoload-path", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/WyriHaximus/php-composer-update-bin-autoload-path.git", - "reference": "33413e3af4f4d7ab4de3653a706aed57f51e84af" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/php-composer-update-bin-autoload-path/zipball/33413e3af4f4d7ab4de3653a706aed57f51e84af", - "reference": "33413e3af4f4d7ab4de3653a706aed57f51e84af", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^2", - "php": "^8 || ^7.4" - }, - "require-dev": { - "wyrihaximus/test-utilities": "^3" - }, - "type": "composer-plugin", - "extra": { - "class": "WyriHaximus\\Composer\\BinAutoloadPathUpdater", - "unused": [ - "php" - ] - }, - "autoload": { - "psr-4": { - "WyriHaximus\\Composer\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "🏰 Composer plugin that fills a bin file with the absolute composer autoload path", - "support": { - "issues": "https://github.com/WyriHaximus/php-composer-update-bin-autoload-path/issues", - "source": "https://github.com/WyriHaximus/php-composer-update-bin-autoload-path/tree/1.1.1" - }, - "funding": [ - { - "url": "https://github.com/WyriHaximus", - "type": "github" - } - ], - "time": "2021-03-14T20:55:38+00:00" - }, - { - "name": "wyrihaximus/constants", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/WyriHaximus/php-constants.git", - "reference": "32ceffdd881593c7fa24d8fcbf9deb58687484cb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/php-constants/zipball/32ceffdd881593c7fa24d8fcbf9deb58687484cb", - "reference": "32ceffdd881593c7fa24d8fcbf9deb58687484cb", - "shasum": "" - }, - "require": { - "php": "^8 || ^7 || ^5.3" - }, - "type": "library", - "autoload": { - "files": [ - "src/Boolean/constants_include.php", - "src/ComposerAutoloader/constants_include.php", - "src/HTTPStatusCodes/constants_include.php", - "src/Numeric/constants_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com", - "homepage": "https://www.wyrihaximus.net/" - } - ], - "description": "Collection of constants for PHP", - "support": { - "issues": "https://github.com/WyriHaximus/php-constants/issues", - "source": "https://github.com/WyriHaximus/php-constants/tree/1.6.0" - }, - "funding": [ - { - "url": "https://github.com/WyriHaximus", - "type": "github" - } - ], - "time": "2020-11-28T12:04:43+00:00" - }, - { - "name": "wyrihaximus/cpu-core-detector", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/WyriHaximus/php-cpu-core-detector.git", - "reference": "287aa2730d8d3a8f581004bb7b95fab1b4e5708f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/php-cpu-core-detector/zipball/287aa2730d8d3a8f581004bb7b95fab1b4e5708f", - "reference": "287aa2730d8d3a8f581004bb7b95fab1b4e5708f", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8", - "react/child-process": "^0.5 || ^0.4 || ^0.6", - "react/event-loop": "^1.1", - "react/promise": "^2.8", - "tivie/php-os-detector": "^1.0", - "wyrihaximus/react-child-process-promise": "^2 || ^3", - "wyrihaximus/ticking-promise": "^1.5 || ^2" - }, - "require-dev": { - "wyrihaximus/async-test-utilities": "^3.3", - "wyrihaximus/test-utilities": "^3" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "WyriHaximus\\CpuCoreDetector\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com" - } - ], - "description": "Detect how many CPU cores are available", - "support": { - "issues": "https://github.com/WyriHaximus/php-cpu-core-detector/issues", - "source": "https://github.com/WyriHaximus/php-cpu-core-detector/tree/2.0.0" - }, - "funding": [ - { - "url": "https://github.com/WyriHaximus", - "type": "github" - } - ], - "time": "2021-03-08T07:46:18+00:00" - }, - { - "name": "wyrihaximus/file-descriptors", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/WyriHaximus/php-file-descriptors.git", - "reference": "de9c3dceecfab88c3f73aa6c9ea5372e7f635d7a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/php-file-descriptors/zipball/de9c3dceecfab88c3f73aa6c9ea5372e7f635d7a", - "reference": "de9c3dceecfab88c3f73aa6c9ea5372e7f635d7a", - "shasum": "" - }, - "require": { - "php": "^8 || ^7.4", - "thecodingmachine/safe": "^2 || ^1", - "tivie/php-os-detector": "^1.1" - }, - "require-dev": { - "wyrihaximus/iterator-or-array-to-array": "^1.1", - "wyrihaximus/test-utilities": "^3.3.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "WyriHaximus\\FileDescriptors\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com" - } - ], - "description": "List open file descriptors for the current process cross platform", - "support": { - "issues": "https://github.com/WyriHaximus/php-file-descriptors/issues", - "source": "https://github.com/WyriHaximus/php-file-descriptors/tree/1.1.1" - }, - "funding": [ - { - "url": "https://github.com/WyriHaximus", - "type": "github" - } - ], - "time": "2024-01-22T13:34:53+00:00" - }, - { - "name": "wyrihaximus/json-throwable", - "version": "4.2.0", - "source": { - "type": "git", - "url": "https://github.com/WyriHaximus/php-json-throwable.git", - "reference": "91c35387bc347dd6fcf37e8baf2588f464a76018" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/php-json-throwable/zipball/91c35387bc347dd6fcf37e8baf2588f464a76018", - "reference": "91c35387bc347dd6fcf37e8baf2588f464a76018", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.5 || ^2.0.0", - "php": "^8 || ^7.4", - "thecodingmachine/safe": "^1.3.3 || ^2.0.0", - "wyrihaximus/json-utilities": "^1.3.1" - }, - "require-dev": { - "wyrihaximus/test-utilities": "^3.3.1 || ^6.0.0" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "WyriHaximus\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com" - } - ], - "description": "📠 JSON encode and decode throwables and exceptions", - "support": { - "issues": "https://github.com/WyriHaximus/php-json-throwable/issues", - "source": "https://github.com/WyriHaximus/php-json-throwable/tree/4.2.0" - }, - "funding": [ - { - "url": "https://github.com/WyriHaximus", - "type": "github" - } - ], - "time": "2024-05-09T13:10:29+00:00" - }, - { - "name": "wyrihaximus/json-utilities", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/WyriHaximus/php-json-utilities.git", - "reference": "53d2f2ee1d7cacb7c7bcd0d1cc2c8483aa0df4b8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/php-json-utilities/zipball/53d2f2ee1d7cacb7c7bcd0d1cc2c8483aa0df4b8", - "reference": "53d2f2ee1d7cacb7c7bcd0d1cc2c8483aa0df4b8", - "shasum": "" - }, - "require": { - "php": "^8.4" - }, - "require-dev": { - "wyrihaximus/makefiles": "^0.6", - "wyrihaximus/test-utilities": "^8.1.0" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "WyriHaximus\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com" - } - ], - "description": "Utilities for php-json-* packages", - "support": { - "issues": "https://github.com/WyriHaximus/php-json-utilities/issues", - "source": "https://github.com/WyriHaximus/php-json-utilities/tree/1.4.0" - }, - "funding": [ - { - "url": "https://github.com/WyriHaximus", - "type": "github" - } - ], - "time": "2025-09-06T21:58:30+00:00" - }, - { - "name": "wyrihaximus/react-child-process-messenger", - "version": "4.0.5", - "source": { - "type": "git", - "url": "https://github.com/WyriHaximus/reactphp-child-process-messenger.git", - "reference": "6323e43a4dcf926de22b6a269a88402564650f12" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/reactphp-child-process-messenger/zipball/6323e43a4dcf926de22b6a269a88402564650f12", - "reference": "6323e43a4dcf926de22b6a269a88402564650f12", - "shasum": "" - }, - "require": { - "cakephp/utility": "^4.2.4", - "doctrine/inflector": "^2.0.3", - "evenement/evenement": "^3.0.1", - "ext-hash": "^8 || ^7.4", - "ext-json": "^8 || ^7.4", - "paragonie/random_compat": "^9.0 || ^2.0", - "php": "^8 || ^7.4", - "react/child-process": "^0.6.2", - "react/event-loop": "^1.1.1", - "react/promise": "^2.8", - "react/promise-stream": "^1.2", - "react/promise-timer": "^1.6", - "react/socket": "^1.6", - "thecodingmachine/safe": "^1.3.3 || ^2.0 || ^3.0", - "wyrihaximus/composer-update-bin-autoload-path": "^1.1.1", - "wyrihaximus/constants": "^1.6", - "wyrihaximus/file-descriptors": "^1.1", - "wyrihaximus/json-throwable": "^4.1", - "wyrihaximus/ticking-promise": "^2 || ^3" - }, - "require-dev": { - "wyrihaximus/async-test-utilities": "^3.4.18" - }, - "type": "library", - "extra": { - "unused": [ - "php", - "react/promise-stream" - ], - "wyrihaximus": { - "bin-autoload-path-update": [ - "bin/child-process" - ] - } - }, - "autoload": { - "psr-4": { - "WyriHaximus\\React\\ChildProcess\\Messenger\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com", - "homepage": "http://wyrihaximus.net/" - } - ], - "description": "Messenger decorator for react/child-process", - "support": { - "issues": "https://github.com/WyriHaximus/reactphp-child-process-messenger/issues", - "source": "https://github.com/WyriHaximus/reactphp-child-process-messenger/tree/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/WyriHaximus", - "type": "github" - } - ], - "time": "2025-04-01T10:46:39+00:00" - }, - { - "name": "wyrihaximus/react-child-process-pool", - "version": "1.9.0", - "source": { - "type": "git", - "url": "https://github.com/WyriHaximus/reactphp-child-process-pool.git", - "reference": "1ad9bc8c00e2dbebdd9559f57175b6f8eb86ce27" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/reactphp-child-process-pool/zipball/1ad9bc8c00e2dbebdd9559f57175b6f8eb86ce27", - "reference": "1ad9bc8c00e2dbebdd9559f57175b6f8eb86ce27", - "shasum": "" - }, - "require": { - "evenement/evenement": "^3.0 || ^2.0", - "php": "^8.0 || ^7.0 || ^5.4", - "react/event-loop": "^1.1", - "wyrihaximus/cpu-core-detector": "^2 || ^1.0.2", - "wyrihaximus/file-descriptors": "^2 || ^1.0 || ^0.1", - "wyrihaximus/react-child-process-messenger": "^4 || ^3 || ^2.10.1", - "wyrihaximus/ticking-promise": "^2 || ^1.5" - }, - "require-dev": { - "clue/block-react": "^1.3", - "phake/phake": "^2.2.1", - "phpunit/phpunit": "^4.8.35||^5.0||^9.5", - "squizlabs/php_codesniffer": "^3.3.2", - "vectorface/dunit": "~2.0" - }, - "suggest": { - "wyrihaximus/react-child-process-pool-redis-queue": "Redis RPC queue" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "WyriHaximus\\React\\ChildProcess\\Pool\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com" - } - ], - "description": "Pool wyrihaximus/react-child-process-messenger processes", - "support": { - "issues": "https://github.com/WyriHaximus/reactphp-child-process-pool/issues", - "source": "https://github.com/WyriHaximus/reactphp-child-process-pool/tree/1.9.0" - }, - "funding": [ - { - "url": "https://github.com/WyriHaximus", - "type": "github" - } - ], - "time": "2023-03-19T21:56:02+00:00" - }, - { - "name": "wyrihaximus/react-child-process-promise", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/WyriHaximus/reactphp-child-process-promise.git", - "reference": "4eb763563dc382dd03b46f9fab0fd1993af68316" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/reactphp-child-process-promise/zipball/4eb763563dc382dd03b46f9fab0fd1993af68316", - "reference": "4eb763563dc382dd03b46f9fab0fd1993af68316", - "shasum": "" - }, - "require": { - "php": "^7.0|^8.0", - "react/child-process": "^0.6 || ^0.5 || ^0.4", - "react/promise": "^2.7", - "wyrihaximus/ticking-promise": "^1.5.2|^2.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0||^9.0", - "sebastian/comparator": "^1.2.4||^4.0", - "squizlabs/php_codesniffer": "^3.3.2", - "vectorface/dunit": "^2.0" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "WyriHaximus\\React\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com", - "homepage": "http://wyrihaximus.net/" - } - ], - "description": "Wrapping ticks into a promise", - "support": { - "issues": "https://github.com/WyriHaximus/reactphp-child-process-promise/issues", - "source": "https://github.com/WyriHaximus/reactphp-child-process-promise/tree/3.0.0" - }, - "funding": [ - { - "url": "https://github.com/WyriHaximus", - "type": "github" - } - ], - "time": "2020-12-04T15:47:08+00:00" - }, - { - "name": "wyrihaximus/ticking-promise", - "version": "2.1.0", - "source": { - "type": "git", - "url": "https://github.com/WyriHaximus/TickingPromise.git", - "reference": "d3903d4bebe8e3c5b11464c0bb81802cdeeb3751" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WyriHaximus/TickingPromise/zipball/d3903d4bebe8e3c5b11464c0bb81802cdeeb3751", - "reference": "d3903d4bebe8e3c5b11464c0bb81802cdeeb3751", - "shasum": "" - }, - "require": { - "php": "^8 || ^7.4", - "react/event-loop": "^1.0", - "react/promise": "^2.8" - }, - "require-dev": { - "wyrihaximus/async-test-utilities": "^3" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "WyriHaximus\\React\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com", - "homepage": "http://wyrihaximus.net/" - } - ], - "description": "Wrapping ticks into a promise", - "support": { - "issues": "https://github.com/WyriHaximus/TickingPromise/issues", - "source": "https://github.com/WyriHaximus/TickingPromise/tree/2.1.0" - }, - "funding": [ - { - "url": "https://github.com/WyriHaximus", - "type": "github" - } - ], - "time": "2020-11-25T12:43:21+00:00" } ], "packages-dev": [], diff --git a/kodorvan/constructor/system/databases/scripts/administrator.php b/kodorvan/constructor/system/databases/scripts/administrator.php new file mode 100644 index 0000000..2614a8b --- /dev/null +++ b/kodorvan/constructor/system/databases/scripts/administrator.php @@ -0,0 +1,77 @@ +database->read( + filter: fn(record $record) => $record->domain === 'buddy_volkodav', + amount: 1, + offset: 0 +)[0] ?? null; + +var_dump($account); + +// Initializing the account authorizations model +$authorizations_model = new authorizations(); + +// Searching for the account authorizations +$authorizations = $authorizations_model->database->read( + filter: fn(record $record) => $record->account === $account->identifier, + update: function (record $record) { + $record->system_settings = 1; + $record->system_deals = 1; + $record->system_projects = 1; + $record->system_invoices = 1; + $record->updated = svoboda::timestamp(); + }, + amount: 1, + offset: 0 +)[0] ?? null; + +var_dump($authorizations); diff --git a/kodorvan/constructor/system/localizations/russian.php b/kodorvan/constructor/system/localizations/russian.php index 110f683..90422bf 100644 --- a/kodorvan/constructor/system/localizations/russian.php +++ b/kodorvan/constructor/system/localizations/russian.php @@ -10,7 +10,8 @@ return [ // Главное меню 'menu_title' => 'Главное меню', 'menu_description_guest' => "🔥 *Создайте ваш первый проект* и получите *ориентировочную стоимость* всего за 2 минуты", - 'menu_description_partner' => "*Благодарю за выбор нашей команды*\. Теперь Вы один из наших %d партнёров!", + 'menu_description_partner' => 'Благодарим за выбор нашей команды', + 'menu_cooperation' => '_Стараемся, чтобы сотрудничество с нами было максимально *комфортным* и *эффективным*_', 'menu_update' => 'Последнее обновление', 'menu_button_project_new' => 'Создать', 'menu_button_projects' => 'Проекты', @@ -23,63 +24,87 @@ return [ 'account_authorized_system_settings' => 'Системный доступ к системным настройкам', // Проект: создание - 'project_create_title' => 'Создание проекта', - /* 'project_create_description' => "Расчитайте ориентировочное время разработки, затем выберите разработчиков и получите стоимость\n\nПосле расчётов можно будет отправить проект в заказ разработчикам и приложить ТЗ, либо краткое описание задачи\n\nМы погружаемся в проекты полностью, поэтому стараемся не распыляться - от степени нагрузки меняется коэффициент стоимости!", */ - 'project_create_description' => "Установите параметры и получите ориентировочное время разработки\n\n_После расчётов можно отправить проект в заказ приложив ТЗ, либо описание задачи_", - 'project_create_warning_cost' => "Стоимость и сроки выполнения предоставлены для планирования и *не являются публичной офертой*", - 'project_create_team_warning' => "", - 'project_create_time' => 'Время', - 'project_create_time_hours' => 'ч', - 'project_create_time_hours_from' => 'от', - 'project_create_time_days' => 'дн', - 'project_create_cost' => 'Стоимость', - 'project_create_cost_prepayment' => 'Предоплата', - 'project_create_team_title' => 'Сбор команды', - 'project_create_team_description' => '_Вы можете *убрать* или *добавить* специалистов, создавая максимально удобное сотрудничество под вашу систему_', - 'project_create_team_warning_cost' => '_*Не влияет на время разработки*_', - 'project_create_team_button_programmers' => 'Программисты: %d%s', - 'project_create_team_button_designers' => 'Дизайнеры: %d%s', - 'project_create_team_button_boosters' => 'Бустеры: %d%s', - 'project_create_cost_title' => 'Стоимость разработки', - 'project_create_cost_description' => 'Введите предложение по *оплате за 1 час* разработки', - 'project_create_cost_default' => '*`%d%s`* \- средняя стоимость с учётом *компетенции*, совокупного опыта, *уникальных* разработок\. Цена уже включает\: *наши сервера*, документирование кода, *передачу кода*, ведение репозитория, *техподдержку* и репутационные гарантии', - 'project_create_cost_warning' => '_Если цена окажется *недостаточной*, мы выставим *справедливое* и *конкурентное* встречное предложение_', - 'project_create_cost_error_distance' => 'Длина сообщения должна быть от %d и до %d символов', - 'project_create_cost_error_not_a_number' => 'Значение должно быть числом', - 'project_create_button_back' => 'Назад', - 'project_create_button_cost_per_hour' => 'Час', - 'project_create_button_request' => 'Заказать', + 'project_title' => 'Создание проекта', + /* 'project_description' => "Расчитайте ориентировочное время разработки, затем выберите разработчиков и получите стоимость\n\nПосле расчётов можно будет отправить проект в заказ разработчикам и приложить ТЗ, либо краткое описание задачи\n\nМы погружаемся в проекты полностью, поэтому стараемся не распыляться - от степени нагрузки меняется коэффициент стоимости!", */ + 'project_description' => "Установите параметры и получите ориентировочное время разработки\n\n_После расчётов можно отправить проект в заказ приложив ТЗ, либо описание задачи_", + 'project_warning_cost' => "Стоимость и сроки выполнения предоставлены для планирования и *не являются публичной офертой*", + 'project_team_warning' => "", + 'project_time' => 'Время', + 'project_time_hours' => 'ч', + 'project_time_hours_from' => 'от', + 'project_time_days' => 'дн', + 'project_cost' => 'Стоимость', + 'project_cost_prepayment' => 'Предоплата', + 'project_team_title' => 'Сбор команды', + 'project_team_description' => '_Вы можете *убрать* или *добавить* специалистов, создавая максимально удобное сотрудничество под вашу систему_', + 'project_team_warning_cost' => '_*Не влияет на время разработки*_', + 'project_team_button_programmers' => 'Программисты: %d%s', + 'project_team_button_designers' => 'Дизайнеры: %d%s', + 'project_team_button_boosters' => 'Бустеры: %d%s', + 'project_team_programmers_title' => 'Количество программистов', + 'project_team_programmers_description' => 'Никаких копий по шаблонам и конструкторов, только *чистый код с нуля* и наши *уникальные технологии* с *многолетней кодовой базой*', + 'project_team_programmers_request' => '_Отправьте предложение по *количеству программистов*_', + 'project_team_programmers_error_amount' => 'Мы можем предоставить до %d программистов', + 'project_team_designers_title' => 'Количество дизайнеров', + 'project_team_designers_description' => 'У каждого дизайнера своё *уникальное видение*, поэтому мы стараемся находить максимально подходящих под проект, но зачастую мы привлекаем сторонних дизайнеров\. Если у заказчика имеются свои проверенные дизайнеры, то мы готовы с ними сотрудничать', + 'project_team_designers_request' => '_Отправьте предложение по *количеству дизайнеров*_', + 'project_team_designers_error_amount' => 'Мы можем предоставить до %d дизайнеров', + 'project_team_boosters_title' => 'Количество бустеров', + 'project_team_boosters_description' => '*Бустер* \- обобщение для специалистов которые занимаются *маркетингом*, *рекламными кабинетами*, дошлифовкой интерфейса, *user\-experience*, А\/Б тестированием, сбором фокус\-группы, развитием сообщества и в целом *SMM*', + 'project_team_boosters_request' => '_Отправьте предложение по *количеству бустеров*_', + 'project_team_boosters_error_amount' => 'Мы можем предоставить до %d бустеров', + 'project_team_error_not_a_number' => 'Значение должно быть числом', + 'project_cost_title' => 'Стоимость разработки', + 'project_cost_description' => '*`%d%s`* \- средняя стоимость с учётом *компетенции*, совокупного опыта, *уникальных* разработок\. Цена уже включает\: *наши сервера*, документирование кода, *передачу кода*, ведение репозитория, *техподдержку* и репутационные гарантии', + 'project_cost_request' => '_Отправьте предложение по *оплате за 1 час* разработки_', + 'project_cost_warning' => '_Если цена окажется *недостаточной*, мы выставим *справедливое* и *конкурентное* встречное предложение_', + 'project_cost_error_distance' => 'Длина сообщения должна быть от %d и до %d символов', + 'project_cost_error_not_a_number' => 'Значение должно быть числом', + 'project_button_back' => 'Назад', + 'project_button_cost_per_hour' => 'Час', + 'project_button_request' => 'Заказать', - 'project_create_architectures_title' => 'Выбор архитектуры проекта', - 'project_create_architectures_description' => 'Каждая архитектура имеет уникальные параметры и коэффициенты \- это основа дальнейших расчётов\!', - 'project_create_button_architecture' => 'Архитектура', - 'project_create_button_architecture_selected' => 'Архитектура', + 'project_architectures_title' => 'Выбор архитектуры проекта', + 'project_architectures_description' => 'Каждая архитектура имеет уникальные параметры и коэффициенты \- это основа дальнейших расчётов\!', + 'project_button_architecture' => 'Архитектура', + 'project_button_architecture_selected' => 'Архитектура', - 'project_create_purposes_title' => 'Выбор назначения', - 'project_create_purposes_description' => 'Вектор разработки, основание проекта', - 'project_create_button_purpose' => 'Назначение', - 'project_create_button_purpose_selected' => 'Назнач.', + 'project_purposes_title' => 'Выбор назначения', + 'project_purposes_description' => 'Вектор разработки, основание проекта', + 'project_button_purpose' => 'Назначение', + 'project_button_purpose_selected' => 'Назнач.', - 'project_create_integrations_title' => 'Выбор интеграций', - 'project_create_integrations_description' => "Синхронизация заказов, товаров, публикаций и прочего в реальном времени, скачивание, загрузка, админ\-панель, рассылка сообщений, подключение аккаунтов\.\.\.\n\n_Отправка запросов в *API*, генерация и перехват *HTTP\-сообщений*, *эмуляция действий пользователя*_", - 'project_create_button_integrations' => 'Интеграции', - 'project_create_button_integrations_selected' => 'Интеграции', - 'project_create_button_team' => 'Команда: %d%s', - 'project_create_peoples' => '', - 'project_create_requested' => 'Проект создан и отправлен оператору', - 'project_create_cancelled' => 'Создание проекта отменено', - - 'project_request_title' => 'Заказ #%d', - 'project_request_architecture' => 'Архитектура', - 'project_request_purpose' => 'Назначение', - 'project_request_hours' => 'Часы', - 'project_request_cost' => 'Стоимость', - 'project_request_team' => 'Команда', - 'project_request_empty' => 'Пусто', - 'project_request_button_accept' => 'Принять', - 'project_request_button_refuse' => 'Отказать', - 'project_request_button_edit' => 'Редактировать', - 'project_request_button_chat' => 'Чат с заказчиком', + 'project_integrations_title' => 'Выбор интеграций', + 'project_integrations_description' => "Синхронизация заказов, товаров, публикаций и прочего в реальном времени, скачивание, загрузка, админ\-панель, рассылка сообщений, подключение аккаунтов\.\.\.\n\n_Отправка запросов в *API*, генерация и перехват *HTTP\-сообщений*, *эмуляция действий пользователя*_", + 'project_button_integrations' => 'Интеграции', + 'project_button_integrations_selected' => 'Интеграции', + 'project_button_team' => 'Команда: %d%s', + 'project_peoples' => '', + 'project_cancelled' => 'Создание проекта отменено', + 'project_deal_requested' => 'Проект создан и отправлен оператору', + 'project_deal_title' => 'Заказ #%d', + 'project_deal_architecture' => 'Архитектура', + 'project_deal_purpose' => 'Назначение', + 'project_deal_time' => 'Время', + 'project_deal_time_hours' => 'ч', + 'project_deal_time_hours_from' => 'от', + 'project_deal_time_days' => 'дн', + 'project_deal_cost' => 'Стоимость', + 'project_deal_team' => 'Команда', + 'project_deal_empty' => 'Пусто', + 'project_deal_button_accept' => 'Принять', + 'project_deal_button_refuse' => 'Отказать', + 'project_deal_button_edit' => 'Редактировать', + 'project_deal_button_chat' => 'Чат с заказчиком', + 'project_accepted_deal_not_found' => 'Не удалось найти заявку', + 'project_accepted_project_not_found' => 'Не удалось найти проект', + 'project_accepted_already_confirmed' => 'Сделка уже проведена', + 'project_accepted_title' => 'Заказ подтверждён\!', + 'project_accepted_description' => 'Мы изучили предложение и *согласились* на условия', + 'project_accepted_prepayment' => 'Предоплата', + 'project_accepted_documents' => '_При желании оформить договор о неразглашении и передаче прав, *обратитесь к оператору*_', + 'project_accepted_confirmed' => 'Подтверждено', + 'project_accepted_button_prepayment' => 'Оплатить через СБП', // Проект: типы 'project_architecture_chat_robot' => 'Чат-робот', @@ -126,14 +151,24 @@ return [ // Авторизация 'authorization_system' => 'Система', 'authorization_settings' => 'Настройки', - 'not_authorized_system' => 'У тебя нет доступа к системе', - 'not_authorized_settings' => 'У тебя нет доступа к настройкам', - 'not_authorized_system_settings' => 'У тебя нет доступа к системным настройкам', + 'not_authorized_system' => 'Запрещён доступ к системе', + 'not_authorized_settings' => 'Запрещён доступ к настройкам', + 'not_authorized_system_settings' => 'Запрещён системный доступ к настройкам', + 'not_authorized_system_deals' => 'Запрещён системный доступ к сделкам', + 'not_authorized_system_projects' => 'Запрещён системный доступ к проектам ', + 'not_authorized_system_invoices' => 'Запрещён системный доступ к счетам', // Сообщения 'message_initialization_fail' => 'Не удалось инициализировать сообщение Телеграм', 'message_text_initialization_fail' => 'Не удалось инициализировать текст сообщения Телеграм', + 'error_title' => 'Перегрузка\!', + 'error_description' => 'Чат\-робот обрабатывает *длинную очередь* запросов', + 'error_repeat' => 'Если не заработает *через 30 минут*, пишите оператору', + 'error_account' => 'Аккаунт', + 'error_button_chat_user' => 'Чат с пользователем', + 'error_button_chat_operator' => 'Чат с оператором', + // Прочее 'why_so_shroomious' => 'почему такой грибъёзный' ]; diff --git a/kodorvan/constructor/system/models/account.php b/kodorvan/constructor/system/models/account.php index 41b44d7..764916a 100644 --- a/kodorvan/constructor/system/models/account.php +++ b/kodorvan/constructor/system/models/account.php @@ -10,7 +10,7 @@ use kodorvan\constructor\models\core, kodorvan\constructor\models\settings, kodorvan\constructor\models\worker, kodorvan\constructor\models\project, - kodorvan\constructor\models\project\enumerations\type as project_type, + kodorvan\constructor\models\project\enumerations\architecture as project_architecture, kodorvan\constructor\models\project\enumerations\status as project_status; // The library for languages support @@ -150,7 +150,7 @@ final class account extends core implements record_interface // Writing the updated record into the account object $this->record = $updated; - // Deserializing parameters + // Deserializing the record $this->deserialize(); // Exit (success) @@ -166,7 +166,7 @@ final class account extends core implements record_interface // Writing the found record into the account object $this->record = $account; - // Deserializing parameters + // Deserializing the record $this->deserialize(); // Exit (success) @@ -374,6 +374,9 @@ final class account extends core implements record_interface if ($authorizations instanceof authorizations) { // Found the account authorizations + // Deserializing the record + $authorizations->deserialize(); + // Exit (success) return $authorizations; } @@ -397,6 +400,9 @@ final class account extends core implements record_interface if ($worker instanceof worker) { // Found the account worker + // Deserializing the record + $worker->deserialize(); + // Exit (success) return $worker; } @@ -420,6 +426,9 @@ final class account extends core implements record_interface if ($settings instanceof settings) { // Found the account settings + // Deserializing the record + $settings->deserialize(); + // Exit (success) return $settings; } @@ -433,23 +442,23 @@ final class account extends core implements record_interface * * Search for the account projects * - * @param project_type|null $type Type of the project + * @param project_architecture|null $architecture architecture of the project * @param project_status|null $status Status of the project * @param int $amount Maximum amount * * @return array The account projects */ public function projects( - ?project_type $type = null, + ?project_architecture $architecture = null, ?project_status $status = null, - int $amount = 20 + int $amount = 1000 ): array { // Search for the account projects $projects = new project()->database->read( filter: fn(record $record) => $record->active === 1 && $record->account === $this->identifier - && ($type === null || $record->type === $type->name) + && ($architecture === null || $record->architecture === $architecture->name) && ($status === null || $record->status === $status->name), amount: $amount ); @@ -475,7 +484,7 @@ final class account extends core implements record_interface filter: fn(record $record) => $record->active === 1 && match (project_status::{$record->status}) { - project_status::developing, project_status::developed, project_status::launched => true, + project_status::developing, project_status::launched => true, default => false }, amount: $amount diff --git a/kodorvan/constructor/system/models/authorizations.php b/kodorvan/constructor/system/models/authorizations.php index 31833bf..bb3b8b8 100644 --- a/kodorvan/constructor/system/models/authorizations.php +++ b/kodorvan/constructor/system/models/authorizations.php @@ -75,8 +75,10 @@ final class authorizations extends core implements record_interface new column('account', type::long_long_unsigned), new column('system', type::char), new column('settings', type::char), - /* new column('', type::char), */ new column('system_settings', type::char), + new column('system_deals', type::char), + new column('system_invoices', type::char), + new column('system_projects', type::char), new column('active', type::char), new column('updated', type::integer_unsigned), new column('created', type::integer_unsigned) @@ -94,6 +96,9 @@ final class authorizations extends core implements record_interface * @param bool $system * @param bool $settings * @param bool $system_settings + * @param bool $system_deals + * @param bool $system_projects + * @param bool $system_invoices * @param bool $active Is the record active? * * @return int|false The record, if created @@ -103,6 +108,9 @@ final class authorizations extends core implements record_interface bool $system = true, bool $settings = true, bool $system_settings = false, + bool $system_deals = false, + bool $system_projects = false, + bool $system_invoices = false, bool $active = true, ): record|false { @@ -112,6 +120,9 @@ final class authorizations extends core implements record_interface (int) $system, (int) $settings, (int) $system_settings, + (int) $system_deals, + (int) $system_projects, + (int) $system_invoices, (int) $active, svoboda::timestamp(), svoboda::timestamp() @@ -142,6 +153,9 @@ final class authorizations extends core implements record_interface $this->record->system = (int) $this->record->system; $this->record->settings = (int) $this->record->settings; $this->record->system_settings = (int) $this->record->system_settings; + $this->record->system_deals = (int) $this->record->system_deals; + $this->record->system_projects = (int) $this->record->system_projects; + $this->record->system_invoices = (int) $this->record->system_invoices; $this->record->active = (int) $this->record->active; // Writing the status of serializing @@ -169,6 +183,9 @@ final class authorizations extends core implements record_interface $this->record->system = (bool) $this->record->system; $this->record->settings = (bool) $this->record->settings; $this->record->system_settings = (bool) $this->record->system_settings; + $this->record->system_deals = (bool) $this->record->system_deals; + $this->record->system_projects = (bool) $this->record->system_projects; + $this->record->system_invoices = (bool) $this->record->system_invoices; $this->record->active = (bool) $this->record->active; // Writing the status of serializing diff --git a/kodorvan/constructor/system/models/deal.php b/kodorvan/constructor/system/models/deal.php new file mode 100644 index 0000000..a175663 --- /dev/null +++ b/kodorvan/constructor/system/models/deal.php @@ -0,0 +1,240 @@ + + */ +final class deal extends core implements record_interface +{ + use record_trait; + + /** + * File + * + * @var string $file Path to the database file + */ + protected string $file = DATABASES . DIRECTORY_SEPARATOR . 'projects' . DIRECTORY_SEPARATOR . 'deals.baza'; + + /** + * Database + * + * @var database $database The database + */ + public protected(set) database $database; + + /** + * Serialized + * + * @var bool $serialized Is the implementator object serialized? + */ + private bool $serialized = true; + + /** + * Constructor + * + * @method record|null $record The record + * + * @return void + */ + public function __construct(?record $record = null) + { + // Initializing the database + $this->database = new database() + ->encoding(encoding::utf8) + ->columns( + new column('identifier', type::long_long_unsigned), + new column('account', type::long_long_unsigned), + new column('project', type::long_long_unsigned), + new column('direction', type::char), + new column('description', type::string, ['length' => 512]), + new column('hours', type::integer_unsigned), + new column('cost', type::float), + new column('payment', type::float), + new column('prepayment', type::float), + new column('programmers', type::integer_unsigned), + new column('designers', type::integer_unsigned), + new column('boosters', type::integer_unsigned), + new column('active', type::char), + new column('confirmed', type::integer_unsigned), + new column('updated', type::integer_unsigned), + new column('created', type::integer_unsigned) + ) + ->connect($this->file); + + // Initializing the record + $record instanceof record and $this->record = $record; + } + + /** + * Write + * + * @throws exception_logic when failed to process project integration + * + * @param int $account The account identifier + * @param int $project The project identifier + * @param deal_direction $direction Direction of the deal + * @param string|null $description Description of the project + * @param int $hours Hours of the project development + * @param int|float $cost Cost per hour of the project development + * @param int|float $payment Payment of the project development + * @param int|float $prepayment Prepayment of the project development + * @param int $programmers Programmers of the project + * @param int $designers Designers of the project + * @param int $boosters Boosters of the project + * @param int $active Is the record active? + * + * @return record|false The record, if created + */ + public function write( + int $account, + int $project, + deal_direction $direction, + ?string $description = null, + int $hours = PROJECT_HOURS_MINIMAL, + int|float $cost = PROJECT_COST_HOUR_DEFAULT, + int|float $payment, + int|float $prepayment, + int $programmers = 0, + int $designers = 0, + int $boosters = 0, + bool $active = true, + ): record|false { + // Initializing the record + $record = $this->database->record( + $this->database->count() + 1, + $account, + $project, + $direction->value, + $description, + $hours, + (float) $cost, + (float) $payment, + (float) $prepayment, + $programmers, + $designers, + $boosters, + (int) $active, + 0, + svoboda::timestamp(), + svoboda::timestamp() + ); + + // Writing the record into the database + $created = $this->database->write($record); + + // Exit (success) + return $created ? $record : false; + } + + /** + * Serialize + * + * @return self The instance from which the method was called (fluent interface) + */ + public function serialize(): self + { + if ($this->serialized) { + // The record implementor is serialized + + // Exit (fail) + throw new exception_runtime('The record implementor is already serialized'); + } + + // Serializing the record parameters + $this->record->direction = $this->record->direction->value; + $this->record->active = (int) $this->record->active; + + // Writing the status of serializing + $this->serialized = true; + + // Exit (success) + return $this; + } + + /** + * Deserialize + * + * @return self The instance from which the method was called (fluent interface) + */ + public function deserialize(): self + { + if (!$this->serialized) { + // The record implementor is deserialized + + // Exit (fail) + throw new exception_runtime('The record implementor is already deserialized'); + } + + // Deserializing the record parameters + $this->record->direction = deal_direction::from($this->record->direction); + $this->record->active = (bool) $this->record->active; + + // Writing the status of serializing + $this->serialized = false; + + // Exit (success) + return $this; + } + + /** + * Project + * + * Search for the project + * + * @return project|null The project + */ + public function project(): ?project + { + // Search for the account project + $project = new project()->read(filter: fn(record $record) => $record->identifier === $this->project && $record->active === 1); + + if ($project instanceof project) { + // Found the account project + + // Deserializing the project + $project->deserialize(); + + // Exit (success) + return $project; + } + + // Exit (fail) + return null; + } +} diff --git a/kodorvan/constructor/system/models/deal/enumerations/direction.php b/kodorvan/constructor/system/models/deal/enumerations/direction.php new file mode 100644 index 0000000..cc9d7d6 --- /dev/null +++ b/kodorvan/constructor/system/models/deal/enumerations/direction.php @@ -0,0 +1,23 @@ + + */ +enum direction: int +{ + case inbound = 0; + case outbound = 1; +} diff --git a/kodorvan/constructor/system/models/project.php b/kodorvan/constructor/system/models/project.php index 225b7e0..c7d880a 100644 --- a/kodorvan/constructor/system/models/project.php +++ b/kodorvan/constructor/system/models/project.php @@ -7,7 +7,10 @@ namespace kodorvan\constructor\models; // Files of the project use kodorvan\constructor\models\core, kodorvan\constructor\models\project\enumerations\status as project_status, - kodorvan\constructor\models\project\enumerations\status as project_type; + kodorvan\constructor\models\project\enumerations\architecture as project_architecture, + kodorvan\constructor\models\project\enumerations\purpose as project_purpose, + kodorvan\constructor\models\project\enumerations\integration as project_integration, + kodorvan\constructor\models\worker\enumerations\type as worker_type; // Baza database use mirzaev\baza\database, @@ -25,6 +28,7 @@ use svoboda\time\statement as svoboda; // Built-in libraries use Exception as exception, + LogicException as exception_logic, RuntimeException as exception_runtime; /** @@ -44,7 +48,7 @@ final class project extends core implements record_interface * * @var string $file Path to the database file */ - protected string $file = DATABASES . DIRECTORY_SEPARATOR . 'project.baza'; + protected string $file = DATABASES . DIRECTORY_SEPARATOR . 'projects.baza'; /** * Database @@ -75,9 +79,15 @@ final class project extends core implements record_interface ->columns( new column('identifier', type::long_long_unsigned), new column('account', type::long_long_unsigned), - new column('status', type::string, ['length' => 16]), - new column('type', type::string, ['length' => 32]), + new column('deal', type::long_long_unsigned), new column('name', type::string, ['length' => 64]), + new column('status', type::string, ['length' => 16]), + new column('architecture', type::string, ['length' => 32]), + new column('purpose', type::string, ['length' => 32]), + new column('integrations', type::integer_unsigned), + /* new column('programmers', type::integer_unsigned), + new column('designers', type::integer_unsigned), + new column('boosters', type::integer_unsigned), */ /* new column('', type::), */ new column('active', type::char), new column('updated', type::integer_unsigned), @@ -92,34 +102,85 @@ final class project extends core implements record_interface /** * Write * + * @throws exception_logic when failed to process project integration + * * @param int $account The account identifier + * @param int|null $deal The deal identifier * @param project_status $status Status of the project - * @param project_type $status Type of the project * @param string|null $name Name of the project + * @param project_architecture|null $architecture Architecture of the project + * @param project_purpose|null $purpose Purpose of the project + * @param int|array $Inegrations Integrations of the project + + * @param int $programmers Programmers of the project + * @param int $designers Designers of the project + * @param int $boosters Boosters of the project + * @param int $active Is the record active? * * @return record|false The record, if created */ public function write( int $account, - project_status $status = project_status::creating, - project_type $type = project_type::special, + ?int $deal = null, ?string $name = null, + project_status $status = project_status::creating, + ?project_architecture $architecture = null, + ?project_purpose $purpose = null, + int|array $integrations = 0b000000, + /* int $programmers = 0, + int $designers = 0, + int $boosters = 0, */ bool $active = true, ): record|false { if (empty($name)) { // Not received the project name // Generating the project name - $name = 'Project №' . count(new account()->read(filter: fn(record $record) => $record->active === 1 && $record->account === $account)?->projects() ?? []); + $name = 'Project №' . count(new account()->read(filter: fn(record $record) => $record->active === 1 && $record->identifier === $account)?->projects() ?? []); } + if (is_array($integrations)) { + // Received integrations in array format + + // Initializing the project integrations buffer + $buffer = 0b000000; + + foreach ($integrations as $integration) { + // Iterating over integrations + + if ($integration instanceof project_integration) { + // Project integration + + // Writing the project integration into the project integrations buffer + $buffer |= $integration->value; + } else { + // Not project integration + + throw new exception_logic('Failed to process project integration'); + } + } + + // Reinitializing the project integrations + $integrations = $buffer; + + // Deinitializing the project integrations buffer + unset($buffer); + } + + // Initializing the record $record = $this->database->record( $this->database->count() + 1, $account, - $status->name, - $type->name, + (int) $deal, $name, + $status->name, + $architecture?->name ?? '', + $purpose?->name ?? '', + $integrations, + /* $programmers, + $designers, + $boosters, */ (int) $active, svoboda::timestamp(), svoboda::timestamp() @@ -147,9 +208,11 @@ final class project extends core implements record_interface } // Serializing the record parameters - $this->record->active = (int) $this->record->active; $this->record->status = $this->record->status->name; - $this->record->type = $this->record->type->name; + $this->record->architecture = $this->record->architecture?->name ?? ''; + $this->record->purpose = $this->record->purpose?->name ?? ''; + $this->record->integrations = project_integration::encode($this->record->integrations); + $this->record->active = (int) $this->record->active; // Writing the status of serializing $this->serialized = true; @@ -173,9 +236,15 @@ final class project extends core implements record_interface } // Deserializing the record parameters - $this->record->active = (bool) $this->record->active; $this->record->status = project_status::{$this->record->status}; - $this->record->type = project_status::{$this->record->type}; + $this->record->architecture = $this->architecture instanceof project_architecture + ? project_architecture::{$this->architecture->type} + : null; + $this->record->purpose = $this->purpose instanceof project_purpose + ? project_purpose::{$this->purpose->type} + : null; + $this->record->integrations = project_integration::decode($this->record->integrations); + $this->record->active = (bool) $this->record->active; // Writing the status of serializing $this->serialized = false; @@ -185,32 +254,205 @@ final class project extends core implements record_interface } /** - * Parameters + * Account * - * Search for all the project properties + * Search for the account * - * @return self The instance from which the method was called (fluent interface) + * @return account|null The account */ - public function parameters(): self + public function account(): ?account { - // Deserializing the record parameters - $this->record->active = (bool) $this->record->active; - $this->record->status = project_status::{$this->record->status}; + // Search for the account account + $account = new account()->read(filter: fn(record $record) => $record->identifier === $this->account && $record->active === 1); - if (!$this->serialized) { - // Not serialized - + if ($account instanceof account) { + // Found the account account - } else { - // Serialized + // Deserializing the record + $account->deserialize(); - // Exit (fail) - throw new exception('The project implementator is serialized'); + // Exit (success) + return $account; } - /* if ($this->record->type === '') */ + // Exit (fail) + return null; + } + + /** + * Hours + * + * Calculate the project development hours + * + * @throws exception_runtime The record is not deserialized + * + * @param bool $absolute Summary all coefficients and then multiply? + * + * @return int|float The project development hours + */ + public function hours(bool $absolute = false): int + { + if ($this->serialized) { + // The record is serialized + + throw new exception_runtime('The record is not deserialized'); + } + + // Initializing start hours + $start = PROJECT_START_HOURS ?? 1; + $start < 1 and $start = 1; + + // Initializing additional hours + $additional = PROJECT_HOURS_ADDITIONAL ?? 0; + + if ($absolute) { + // The absolute coefficient + + // Declaring coefficient + $coefficient = PROJECT_START_COEFFICIENT ?? 0; + + if (isset($this->architecture)) { + // Initialized the project architecture + + // Adding into the coefficient + $coefficient += $this->architecture->coefficient() ?? 0; + } + + if (isset($this->purpose)) { + // Initialized the project purpose + + // Adding into the coefficient + $coefficient += $this->purpose->coefficient() ?? 0; + } + + if (!empty($this->integrations)) { + // Initialized the project integrations + + foreach ($this->integrations as $integration) { + // Iterating over the project integrations + + // Adding into the coefficient + $coefficient += $integration->coefficient() ?? 0; + } + } + + // Calculating the development hours + $hours = $start * $coefficient + $additional; + + // Calculating and exit (success) + return (int) ceil(max($hours, PROJECT_HOURS_MINIMAL)); + } else { + // The relative coefficient + + // Initializing the development hours + $hours = $start; + + if (isset($this->architecture)) { + // Initialized the project architecture + + // Adding into the coefficient + $hours *= $this->architecture->coefficient() ?? 1; + } + + if (isset($this->purpose)) { + // Initialized the project purpose + + // Adding into the coefficient + $hours *= $this->purpose->coefficient() ?? 1; + } + + if (!empty($this->integrations)) { + // Initialized the project integrations + + foreach ($this->integrations as $integration) { + // Iterating over the project integrations + + // Adding into the coefficient + $hours *= $integration->coefficient() ?? 1; + } + } + + // Calculating with additional hours + $hours += $additional; + + // Calculating and exit (success) + return (int) ceil(max($hours, PROJECT_HOURS_MINIMAL)); + } + } + + /** + * Payment + * + * Calculate the project development payment + * + * @param int|float $cost Cost per hour + * @param int $hours The project development hours + * @param int $programmers Programmers + * @param int $designers Designers + * @param int $boosters Boosters + * + * @return array ['full' => int|float, 'prepayment' => int|float] + */ + public function payment( + int|float $cost = PROJECT_COST_HOUR_DEFAULT, + int $hours = PROJECT_HOURS_MINIMAL, + int $programmers = 0, + int $designers = 0, + int $boosters = 0 + ): array { + // Initializing costs + $costs = [ + 'full' => ceil($hours * $cost), + 'prepayment' => null + ]; + + // Initializing default workers amounts + $default = [ + 'programmers' => $this->architecture?->workers()[worker_type::programmer->name] ?? 0, + 'designers' => $this->architecture?->workers()[worker_type::designer->name] ?? 0, + 'boosters' => $this->architecture?->workers()[worker_type::booster->name] ?? 0 + ]; + + if ($programmers > $default['programmers']) { + // Programmers amount more than default + + // Calculating the full cost + $costs['full'] *= $programmers * PROJECT_WORKERS_PROGRAMMERS_COEFFICIENT; + } else if ($programmers < $default['programmers']) { + // Programmers amount less than default + + // Calculating the full cost + $costs['full'] /= max($programmers, 1) * PROJECT_WORKERS_PROGRAMMERS_COEFFICIENT; + } + + if ($designers > $default['designers']) { + // Designers amount more than default + + // Calculating the full cost + $costs['full'] *= $designers * PROJECT_WORKERS_DESIGNERS_COEFFICIENT; + } else if ($designers < $default['designers']) { + // Designers amount less than default + + // Calculating the full cost + $costs['full'] /= max($designers, 1) * PROJECT_WORKERS_DESIGNERS_COEFFICIENT; + } + + if ($boosters > $default['boosters']) { + // Boosters amount more than default + + // Calculating the full cost + $costs['full'] *= $boosters * PROJECT_WORKERS_BOOSTERS_COEFFICIENT; + } else if ($boosters < $default['boosters']) { + // Boosters amount less than default + + // Calculating the full cost + $costs['full'] /= max($boosters, 1) * PROJECT_WORKERS_BOOSTERS_COEFFICIENT; + } + + // Calculating the prepayment + $costs['prepayment'] = ceil($costs['full'] * (PROJECT_COST_PREPAYMENT_PERCENTS / 100)); // Exit (success) - return $this; + return $costs; } } diff --git a/kodorvan/constructor/system/models/project/enumerations/integration.php b/kodorvan/constructor/system/models/project/enumerations/integration.php index 82d8241..c59e327 100644 --- a/kodorvan/constructor/system/models/project/enumerations/integration.php +++ b/kodorvan/constructor/system/models/project/enumerations/integration.php @@ -19,14 +19,14 @@ use InvalidArgumentException as exception_argument, * @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License * @author Arsen Mirzaev Tatyano-Muradovich */ -enum integration +enum integration: int { - case one_c; - case bitrix24; - case moy_sklad; - case telegram; - case mail; - case excel; + case one_c = 0b000001; + case bitrix24 = 0b000010; + case moy_sklad = 0b000100; + case telegram = 0b001000; + case mail = 0b010000; + case excel = 0b100000; /** * Label @@ -96,4 +96,54 @@ enum integration default => 2 }; } + + /** + * Decode + * + * @param int $bitmask The encoded cases + * + * @return array Decoded cases + */ + public static function decode(int $bitmask): array + { + // Initializing the registry of decoded cases + $decoded = []; + + foreach (static::cases() as $case) { + // Iterating over cases + + if ($bitmask & $case->value) { + // Decoded the case + + // Decoding the case and writing into the registry of decoded cases + $decoded[] = $case; + } + } + + // Exit (success) + return $decoded; + } + + /** + * Encode + * + * @param array $cases The decoded cases + * + * @return int Encoded cases bitmask + */ + public static function encode(array $cases):int + { + // Initializing the registry of encoded cases + $encoded = 0b000000; + + foreach ($cases as $case) { + // Iterating over cases + + // Encoding the case and writing into the registry of encoded cases + $encoded |= $case->value; + } + + // Exit (success) + return $encoded; + } } diff --git a/kodorvan/constructor/system/models/project/enumerations/purpose.php b/kodorvan/constructor/system/models/project/enumerations/purpose.php index 2444ebc..2967fa6 100644 --- a/kodorvan/constructor/system/models/project/enumerations/purpose.php +++ b/kodorvan/constructor/system/models/project/enumerations/purpose.php @@ -95,10 +95,10 @@ enum purpose language::en => 'Calculate', language::ru => 'Расчёты' }, - /* static::logic => match ($language) { + static::logic => match ($language) { language::en => 'Logic', language::ru => 'Логика' - }, */ + }, static::game => match ($language) { language::en => 'Game', language::ru => 'Игра' diff --git a/kodorvan/constructor/system/models/project/enumerations/status.php b/kodorvan/constructor/system/models/project/enumerations/status.php index 8a7dc9e..e849c06 100644 --- a/kodorvan/constructor/system/models/project/enumerations/status.php +++ b/kodorvan/constructor/system/models/project/enumerations/status.php @@ -19,12 +19,8 @@ use InvalidArgumentException as exception_argument, enum status { case creating; - case calculated; case requested; - case invoiced; - case developing; - case developed; case launched; } diff --git a/kodorvan/constructor/system/models/telegram/commands/start.php b/kodorvan/constructor/system/models/telegram/commands/start.php index 839c64c..316bbc0 100644 --- a/kodorvan/constructor/system/models/telegram/commands/start.php +++ b/kodorvan/constructor/system/models/telegram/commands/start.php @@ -82,10 +82,6 @@ final class start extends command // Initializing the account $account = $robot->get('account'); - // Initializing the message last update text - exec(command: 'git log --oneline $(git describe --tags --abbrev=0 @^ --always)..@ -1 --format="%at" | xargs -I{} date -d @{} "+%Y.%m.%d %H:%M"', output: $git); - $update = empty($git[0]) ? '' : "🔏 *$localization->menu_update:* " . unmarkdown($git[0]); - // Calculating amount of projects $projects = count($account->projects()); @@ -115,14 +111,42 @@ final class start extends command ) ); + // Title + $title = "📋 *$localization->menu_title*"; + + // Declaring the message variables + $welcome = $cooperation = null; + + if ($projects > 0) { + // The account have projects + + // Welcome + $welcome = "🤟 *$localization->menu_description_partner*"; + + // Cooperation + $cooperation = $localization->menu_cooperation; + } else { + // The account have not projects + + // Welcome + $welcome = $localization->menu_description_guest; + } + + // Update + /* exec(command: 'git log --oneline $(git describe --tags --abbrev=0 @^ --always)..@ -1 --format="%at" | xargs -I{} date -d @{} "+%Y\.%m\.%d %H:%M"', output: $git); // Formatted */ + exec(command: 'git log --oneline $(git describe --tags --abbrev=0 @^ --always)..@ -1 --format="%at"', output: $git); + $update = empty($git[0]) ? '' : "🔏 *$localization->menu_update:* ![" . $git[0] . '](tg://time?unix=' . $git[0] . '&format=r)'; + + // Sending the message $robot->sendMessage( text: implode( "\n\n", - [ - "📋 *$localization->menu_title*", - $projects > 0 ? printf($localization->menu_description_partner, $partners) : $localization->menu_description_guest, + array_filter([ + $title, + $welcome, + $cooperation, $update - ] + ]) ), parse_mode: mode::MARKDOWN, disable_notification: true, diff --git a/kodorvan/constructor/system/models/telegram/conversations/project/create.php b/kodorvan/constructor/system/models/telegram/conversations/project.php similarity index 65% rename from kodorvan/constructor/system/models/telegram/conversations/project/create.php rename to kodorvan/constructor/system/models/telegram/conversations/project.php index f98c010..446af3c 100644 --- a/kodorvan/constructor/system/models/telegram/conversations/project/create.php +++ b/kodorvan/constructor/system/models/telegram/conversations/project.php @@ -2,16 +2,20 @@ declare(strict_types=1); -namespace kodorvan\constructor\models\telegram\conversations\project; +namespace kodorvan\constructor\models\telegram\conversations; // Files of the project use kodorvan\constructor\models\core, kodorvan\constructor\models\account, kodorvan\constructor\models\localization, kodorvan\constructor\models\settings, + kodorvan\constructor\models\deal, + kodorvan\constructor\models\deal\enumerations\direction as deal_direction, + kodorvan\constructor\models\project as model, kodorvan\constructor\models\project\enumerations\architecture as project_architecture, kodorvan\constructor\models\project\enumerations\purpose as project_purpose, kodorvan\constructor\models\project\enumerations\integration as project_integration, + kodorvan\constructor\models\project\enumerations\status as project_status, kodorvan\constructor\models\worker\enumerations\type as worker_type, kodorvan\constructor\models\telegram\processes\language\select as process_language_select; @@ -21,6 +25,13 @@ use mirzaev\languages\language; // The library for escaping all markdown symbols use function mirzaev\unmarkdown; +// Baza database +use mirzaev\baza\database, + mirzaev\baza\column, + mirzaev\baza\record, + mirzaev\baza\enumerations\encoding, + mirzaev\baza\enumerations\type; + // Framework for Telegram use SergiX44\Nutgram\Nutgram as telegram, SergiX44\Nutgram\Conversations\InlineMenu as menu, @@ -32,7 +43,8 @@ use SergiX44\Nutgram\Nutgram as telegram, SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardButton as button; // Built-in libraries -use Error as error; +use Exception as exception, + Error as error; /** * Telegram project @@ -42,42 +54,28 @@ use Error as error; * @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License * @author Arsen Mirzaev Tatyano-Muradovich */ -final class create extends menu +final class project extends menu { - /** - * Text - * - * @var string $text The message text + /* + * Instance + * + * @var model $instance The project instance */ - public string $text = ''; + public model $instance; /** - * Architecture + * Previous * - * @var project_architecture $architecture The project architecture + * @var string $previous The message previous text */ - public project_architecture $architecture; - - /** - * Purpose - * - * @var project_purpose $purpose The project purpose - */ - public project_purpose $purpose; - - /** - * Integrations - * - * @var array $integrations The project integrations - */ - public array $integrations = []; + public string $previous = ''; /** * Cost * * @var int|float $cost Cost per hour */ - public int|float $cost = PROJECT_CREATE_COST_HOUR_DEFAULT ?? 0; + public int|float $cost = PROJECT_COST_HOUR_DEFAULT ?? 0; /** * Messages @@ -97,6 +95,13 @@ final class create extends menu */ public array $workers = []; + /** + * Description + * + * @var string $description The project description (512 symbols) + */ + public string $description = ''; + /** * Start * @@ -107,13 +112,23 @@ final class create extends menu * * @return void */ - public function start(telegram $robot, bool $new = true): void + public function start(telegram $robot, bool $new = true, ?model $instance = null): void { + // Sending the "typing" action + /* $robot->sendChatAction('typing'); */ + if ($new) { // New // Ending the conversation $robot->endConversation(); + + if ($instance instanceof model) { + // Received the project instance + + // Writing into the property + $this->instance = $instance; + } } // Deleting the message buttons @@ -129,46 +144,52 @@ final class create extends menu $account = $robot->get('account'); // Title - $title = "🏛 *$localization->project_create_title*"; + $title = "🏛 *$localization->project_title*"; // Declaring the message generation variables - $costs = $warnings = []; + $payment = $warnings = []; $welcome = $time = null; + // Initializing the project development workers + if (empty($this->workers)) $this->workers = $this->instance->architecture?->workers() ?? []; + if ($new) { // New // Writing the project create message content - $welcome = $localization->project_create_description; + $welcome = $localization->project_description; } else { // Continue // Hours - $hours = $this->hours(); + $hours = $this->instance->hours(); // Days - $days = ceil(($hours / PROJECT_CREATE_DAY_HOURS) + PROJECT_CREATE_DAY_ADDITIONAL); + $days = ceil(($hours / PROJECT_DAY_HOURS) + PROJECT_DAY_ADDITIONAL); // Writing the project create message content (hours and days) - $time = "*$localization->project_create_time:* $hours$localization->project_create_time_hours _\($days$localization->project_create_time_days\)_"; + $time = "*$localization->project_time:* $hours$localization->project_time_hours _\($days$localization->project_time_days\)_"; if (isset($this->cost)) { // Initialized the project development cost - // Full cost - $full = ceil($hours * $this->cost); - - // Prepayment - $prepayment = ceil($full * (PROJECT_CREATE_COST_PREPAYMENT_PERCENTS / 100)); + // Calculating the project development costs + $costs = $this->instance->payment( + cost: $this->cost, + hours: $hours, + programmers: $this->workers[worker_type::programmer->name] ?? 0, + designers: $this->designers[worker_type::designer->name] ?? 0, + boosters: $this->boosters[worker_type::booster->name] ?? 0 + ); // Writing the project create message full cost - $costs['full'] = "*$localization->project_create_cost:* $full" . $account->currency->symbol(); + $payment['full'] = "*$localization->project_cost:* " . $costs['full'] . $account->currency->symbol(); // Writing the project create message cost prepayment - $costs['prepayment'] = "*$localization->project_create_cost_prepayment:* $prepayment" . $account->currency->symbol() . ' _\(' . PROJECT_CREATE_COST_PREPAYMENT_PERCENTS . '%\)_'; + $payment['prepayment'] = "*$localization->project_cost_prepayment:* " . $costs['prepayment'] . $account->currency->symbol() . ' _\(' . PROJECT_COST_PREPAYMENT_PERCENTS . '%\)_'; // Writing the project create message cost warning - $warnings['cost'] = "⚠️ " . $localization->project_create_warning_cost; + $warnings['cost'] = "⚠️ $localization->project_warning_cost"; } } @@ -180,13 +201,13 @@ final class create extends menu $title, $welcome, $time, - implode("\n", $costs), + implode("\n", $payment), implode("\n", $warnings), ] ) ); - if ($this->text !== $text) { + if ($this->previous !== $text) { // The message text was changed $this->menuText( @@ -195,6 +216,9 @@ final class create extends menu 'parse_mode' => mode::MARKDOWN ] ); + + // Saving the message text + $this->previous = $text; } // Initializing the row @@ -203,7 +227,7 @@ final class create extends menu // Initializing the maximum amount of buttons in a row $break = 3; - if (isset($this->architecture)) { + if (isset($this->instance->architecture)) { // Initialized the project architecture // Initializing the buffer for the first row @@ -211,16 +235,16 @@ final class create extends menu // Writing the project architecture button into the buffer of the first row $first[0] = button::make( - text: $localization['project_architecture_' . $this->architecture?->name] ?? $this->architecture?->label(language: $language), + text: $localization['project_architecture_' . $this->instance->architecture?->name] ?? $this->instance->architecture?->label(language: $language), callback_data: '@architectures' ); - if (isset($this->purpose)) { + if (isset($this->instance->purpose)) { // Initialized the project purpose // Writing the project purpose button into the buffer of the first row $first[1] = button::make( - text: $localization['project_purpose_' . $this->purpose?->name] ?? $this->purpose?->label(language: $language), + text: $localization['project_purpose_' . $this->instance->purpose?->name] ?? $this->instance->purpose?->label(language: $language), callback_data: '@purposes' ); @@ -228,7 +252,7 @@ final class create extends menu $this->addButtonRow(...$first); // Initializing the project integrations - $integrations = $this->purpose->integrations(); + $integrations = $this->instance->purpose->integrations(); if (!empty($integrations)) { // Integrations @@ -240,7 +264,7 @@ final class create extends menu ', ', array_map( fn(project_integration $integration) => $localization['project_integration_' . $integration?->name] ?? $integration?->label($language) ?? '', - $this->integrations, + $this->instance->integrations, ) ), ' ' @@ -249,7 +273,7 @@ final class create extends menu // Writing the project integrations button into the buffer of the first row $row[] = button::make( - text: empty($text) ? $localization->project_create_button_integrations : $text, + text: empty($text) ? $localization->project_button_integrations : $text, callback_data: '@integrations' ); @@ -265,7 +289,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::chat_robot, project_architecture::parser, project_architecture::site, @@ -284,7 +308,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -295,7 +319,7 @@ final class create extends menu if (isset($this->interface)) { // Initialized the project interface - if ($this->architecture === project_architecture::program) { + if ($this->instance->architecture === project_architecture::program) { // Program // mobile or desktop @@ -303,7 +327,7 @@ final class create extends menu } else { // Not initialized the project interface - if ($this->architecture === project_architecture::program) { + if ($this->instance->architecture === project_architecture::program) { // Program // mobile or desktop @@ -311,7 +335,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::chat_robot, project_architecture::parser, project_architecture::site, @@ -330,7 +354,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::chat_robot, project_architecture::parser, project_architecture::site, @@ -349,7 +373,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -366,7 +390,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -383,7 +407,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::chat_robot, project_architecture::parser, project_architecture::site, @@ -402,7 +426,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::chat_robot, project_architecture::site, project_architecture::program, @@ -420,7 +444,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::chat_robot, project_architecture::parser, project_architecture::site, @@ -438,7 +462,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::chat_robot, project_architecture::site, project_architecture::program, @@ -456,7 +480,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::chat_robot, project_architecture::site, project_architecture::complex => true, @@ -473,7 +497,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::chat_robot, project_architecture::parser, project_architecture::site, @@ -492,7 +516,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::chat_robot, project_architecture::site, project_architecture::program, @@ -510,7 +534,7 @@ final class create extends menu } } - if (match ($this->architecture) { + if (match ($this->instance->architecture) { project_architecture::chat_robot, project_architecture::parser, project_architecture::site, @@ -533,7 +557,7 @@ final class create extends menu // Writing the project purpose button into the buffer of the first row $first[1] = button::make( - text: "🔸 $localization->project_create_button_purpose", + text: "🔸 $localization->project_button_purpose", callback_data: '@purposes' ); @@ -546,7 +570,7 @@ final class create extends menu // Writing the project architecture button $this->addButtonRow( button::make( - text: "🔸 $localization->project_create_button_architecture", + text: "🔸 $localization->project_button_architecture", callback_data: '@architectures' ) ); @@ -566,10 +590,7 @@ final class create extends menu // The project development hours was calculated // Cost - $cost = '🛠 ' . (isset($this->cost) ? "$localization->project_create_button_cost_per_hour: $this->cost" . $account->currency->symbol() : $localization->project_create_button_cost_per_hour); - - // Initializing the project development workers - if (empty($this->workers)) $this->workers = $this->architecture?->workers() ?? []; + $cost = '🛠 ' . (isset($this->cost) ? "$localization->project_button_cost_per_hour: $this->cost" . $account->currency->symbol() : $localization->project_button_cost_per_hour); // Writing the project buttons $this->addButtonRow( @@ -578,7 +599,7 @@ final class create extends menu callback_data: 'set@cost' ), button::make( - text: '🤠 ' . sprintf($localization->project_create_button_team, count($this->workers), $localization->project_create_peoples), + text: '🤠 ' . sprintf($localization->project_button_team, array_sum($this->workers), $localization->project_peoples), callback_data: 'open@team' ) ); @@ -587,14 +608,14 @@ final class create extends menu // Writing the project cost per hour button $this->addButtonRow( button::make( - text: "📦 $localization->project_create_button_request", + text: "📦 $localization->project_button_request", callback_data: '@request' ) ); } - // Updating the message and saving its text - $this->text = $this->orNext('stop')->showMenu()->text; + // Updating the message + $this->orNext('stop')->showMenu(); } /** @@ -623,6 +644,9 @@ final class create extends menu */ public function team(telegram $robot): void { + // Sending the "typing" action + /* $robot->sendChatAction('typing'); */ + // Initializing the account language $language = $robot->get('language') ?? LANGUAGE_DEFAULT; @@ -630,7 +654,7 @@ final class create extends menu $localization = $robot->get('localization') ?? new localization($language); // Initializing the project development workers - $this->workers ??= $this->architecture?->workers() ?? []; + if (empty($this->workers)) $this->workers = $this->instance->architecture?->workers() ?? []; // Clearing the message buttons $this->clearButtons(); @@ -638,39 +662,39 @@ final class create extends menu // Writing the row into the keyboard $this->addButtonRow( button::make( - text: sprintf("🥷🏻 $localization->project_create_team_button_programmers", $this->workers[worker_type::programmer->name] ?? [], $localization->project_create_peoples), - callback_data: '@programmers' + text: sprintf("🥷🏻 $localization->project_team_button_programmers", $this->workers[worker_type::programmer->name] ?? [], $localization->project_peoples), + callback_data: 'set@programmers' ) ); // Writing the row into the keyboard $this->addButtonRow( button::make( - text: sprintf("👽 $localization->project_create_team_button_designers", $this->workers[worker_type::designer->name] ?? [], $localization->project_create_peoples), - callback_data: '@designers' + text: sprintf("👽 $localization->project_team_button_designers", $this->workers[worker_type::designer->name] ?? [], $localization->project_peoples), + callback_data: 'set@designers' ), button::make( - text: sprintf("🦹🏻‍♀️ $localization->project_create_team_button_boosters", $this->workers[worker_type::booster->name] ?? [], $localization->project_create_peoples), - callback_data: '@boosters' + text: sprintf("🦹🏻‍♀️ $localization->project_team_button_boosters", $this->workers[worker_type::booster->name] ?? [], $localization->project_peoples), + callback_data: 'set@boosters' ) ); // Writing the row into the keyboard $this->addButtonRow( button::make( - text: "🔏 $localization->project_create_button_back", + text: "🔏 $localization->project_button_back", callback_data: '@continue' ) ); // Title - $title = "🤠 $localization->project_create_team_title"; + $title = "🤠 $localization->project_team_title"; // Description - $description = $localization->project_create_team_description; + $description = $localization->project_team_description; // Warning: cost - $warning_cost = '⚠️ ' . $localization->project_create_team_warning_cost; + $warning_cost = '⚠️ ' . $localization->project_team_warning_cost; // Generating the message text $text = implode( @@ -684,16 +708,23 @@ final class create extends menu ) ); - // Updating the message text - $this->menuText( - text: $text, - opt: [ - 'parse_mode' => mode::MARKDOWN - ] - ); + if ($this->previous !== $text) { + // The message text was changed - // Updating the message - $this->showMenu(); + // Updating the message text + $this->menuText( + text: $text, + opt: [ + 'parse_mode' => mode::MARKDOWN + ] + ); + + // Saving the message text + $this->previous = $text; + } + + // Updating the message + $this->orNext('continue')->showMenu(); } /** @@ -707,6 +738,9 @@ final class create extends menu */ public function architectures(telegram $robot): void { + // Sending the "typing" action + /* $robot->sendChatAction('typing'); */ + // Initializing the account language $language = $robot->get('language') ?? LANGUAGE_DEFAULT; @@ -716,22 +750,32 @@ final class create extends menu // Initializing the account $account = $robot->get('account'); - // Updating the message text - $this->menuText( - text: implode( - "\n\n", - array_filter( - [ - "⚙️ *$localization->project_create_architectures_title*", - $localization->project_create_architectures_description, - ] - ) - ), - opt: [ - 'parse_mode' => mode::MARKDOWN - ] + // Generating the message text + $text = implode( + "\n\n", + array_filter( + [ + "⚙️ *$localization->project_architectures_title*", + $localization->project_architectures_description, + ] + ) ); + if ($this->previous !== $text) { + // The message text was changed + + // Updating the message text + $this->menuText( + text: $text, + opt: [ + 'parse_mode' => mode::MARKDOWN + ] + ); + + // Saving the message text + $this->previous = $text; + } + // Deleting the message buttons $this->clearButtons(); @@ -747,11 +791,11 @@ final class create extends menu // Initializing buffer of architectures $architectures = project_architecture::cases(); - if (isset($this->architecture)) { + if (isset($this->instance->architecture)) { // Initialized the selected architecture // Initializing the selected purpose index - $selected = array_search($this->architecture ?? null, $architectures, strict: true); + $selected = array_search($this->instance->architecture ?? null, $architectures, strict: true); if ($selected !== false) { // Found the selected architecture index @@ -838,8 +882,8 @@ final class create extends menu // Deinitializing deprecated variables unset($row, $limit, $length, $generated, $architectures, $architecture); - // Updating the message and saving its text - $this->text = $this->showMenu()->text; + // Updating the message + $this->orNext('continue')->showMenu(); } /** @@ -860,14 +904,14 @@ final class create extends menu $localization = $robot->get('localization') ?? new localization($language); // Initializing the project architecture - $this->architecture = project_architecture::{$robot->callbackQuery()->data}; + $this->instance->architecture = project_architecture::{$robot->callbackQuery()->data}; // Clearing from deprecated parameters $this->clear(); // Sending the popup notification $robot->answerCallbackQuery( - text: $localization['project_architecture_' . $this->architecture?->name] ?? $this->architecture?->label(language: $language), + text: $localization['project_architecture_' . $this->instance->architecture?->name] ?? $this->instance->architecture?->label(language: $language), show_alert: false ); @@ -889,6 +933,9 @@ final class create extends menu */ public function purposes(telegram $robot): void { + // Sending the "typing" action + /* $robot->sendChatAction('typing'); */ + // Initializing the account language $language = $robot->get('language') ?? LANGUAGE_DEFAULT; @@ -898,20 +945,30 @@ final class create extends menu // Initializing the account $account = $robot->get('account'); - // Updating the message text - $this->menuText( - text: implode( - "\n\n", - array_filter([ - "🛠 *$localization->project_create_purposes_title*", - $localization->project_create_purposes_description, - ]) - ), - opt: [ - 'parse_mode' => mode::MARKDOWN - ] + // Generating the message text + $text = implode( + "\n\n", + array_filter([ + "🛠 *$localization->project_purposes_title*", + $localization->project_purposes_description, + ]) ); + if ($this->previous !== $text) { + // The message text was changed + + // Updating the message text + $this->menuText( + text: $text, + opt: [ + 'parse_mode' => mode::MARKDOWN + ] + ); + + // Saving the message text + $this->previous = $text; + } + // Deleting the message buttons $this->clearButtons(); @@ -925,13 +982,13 @@ final class create extends menu $break = 4; // Initializing buffer of purposes - $purposes = $this->architecture->purposes(); + $purposes = $this->instance->architecture->purposes(); - if (isset($this->purpose)) { + if (isset($this->instance->purpose)) { // Initialized the selected purpose // Initializing the selected purpose index - $selected = array_search($this->purpose ?? null, $purposes, strict: true); + $selected = array_search($this->instance->purpose ?? null, $purposes, strict: true); if ($selected !== false) { // Found the selected purpose index @@ -1028,8 +1085,8 @@ final class create extends menu // Deinitializing deprecated variables unset($row, $limit, $length, $generated, $purposes, $purpose); - // Updating the message and saving its text - $this->text = $this->showMenu()->text; + // Updating the message + $this->orNext('continue')->showMenu(); } /** @@ -1050,14 +1107,11 @@ final class create extends menu $localization = $robot->get('localization') ?? new localization($language); // Initializing the project purpose - $this->purpose = project_purpose::{$robot->callbackQuery()->data}; - - // Clearing from deprecated parameters - $this->clear(); + $this->instance->purpose = project_purpose::{$robot->callbackQuery()->data}; // Sending the popup notification $robot->answerCallbackQuery( - text: $localization['project_purpose_' . $this->purpose?->name] ?? $this->purpose?->label(language: $language), + text: $localization['project_purpose_' . $this->instance->purpose?->name] ?? $this->instance->purpose?->label(language: $language), show_alert: false ); @@ -1079,6 +1133,9 @@ final class create extends menu */ public function integrations(telegram $robot): void { + // Sending the "typing" action + /* $robot->sendChatAction('typing'); */ + // Initializing the account language $language = $robot->get('language') ?? LANGUAGE_DEFAULT; @@ -1088,20 +1145,30 @@ final class create extends menu // Initializing the account $account = $robot->get('account'); - // Updating the message text - $this->menuText( - text: implode( - "\n\n", - array_filter([ - "📡 *$localization->project_create_integrations_title*", - $localization->project_create_integrations_description, - ]) - ), - opt: [ - 'parse_mode' => mode::MARKDOWN - ] + // Generating the message text + $text = implode( + "\n\n", + array_filter([ + "📡 *$localization->project_integrations_title*", + $localization->project_integrations_description, + ]) ); + if ($this->previous !== $text) { + // The message text was changed + + // Updating the message text + $this->menuText( + text: $text, + opt: [ + 'parse_mode' => mode::MARKDOWN + ] + ); + + // Saving the message text + $this->previous = $text; + } + // Deleting the message buttons $this->clearButtons(); @@ -1115,7 +1182,7 @@ final class create extends menu $break = 4; // Initializing buffer of integrations - $integrations = $this->purpose->integrations(); + $integrations = $this->instance->purpose->integrations(); // Declaring the generated buttons registry $generated = []; @@ -1143,7 +1210,7 @@ final class create extends menu $length += $integration->length(); // Initializing the target - $target = $this->integrations[$integration->name] ?? null; + $target = $this->instance->integrations[$integration->name] ?? null; // Writing the integration button into the row $row[] = button::make( @@ -1170,7 +1237,7 @@ final class create extends menu $length = 0; // Initializing the target - $target = $this->integrations[$integration->name] ?? null; + $target = $this->instance->integrations[$integration->name] ?? null; // Writing the button into the menu $this->addButtonRow(button::make( @@ -1193,7 +1260,7 @@ final class create extends menu // Writing the "back" button into the menu $this->addButtonRow( button::make( - text: "🔏 $localization->project_create_button_back", + text: "🔏 $localization->project_button_back", callback_data: '@continue' ) ); @@ -1201,8 +1268,8 @@ final class create extends menu // Deinitializing deprecated variables unset($row, $limit, $length, $generated, $integrations, $integration); - // Updating the message and saving its text - $this->text = $this->showMenu()->text; + // Updating the message + $this->orNext('continue')->showMenu(); } /** @@ -1225,25 +1292,25 @@ final class create extends menu // Initializing the integration $integration = project_integration::{$robot->callbackQuery()->data}; - if (isset($this->integrations[$integration->name])) { + if (isset($this->instance->integrations[$integration->name])) { // Enabled // Disabling - unset($this->integrations[$integration->name]); + unset($this->instance->integrations[$integration->name]); } else { // Disabled // Enabling - $this->integrations[$integration->name] = $integration; + $this->instance->integrations = [$integration->name => $integration] + ($this->instance->integrations ?? []); }; // Sending the popup notification $robot->answerCallbackQuery( - text: $localization['project_integrations_' . (isset($this->integrations[$integration->name]) ? 'enabled' : 'disabled')], + text: $localization['project_integrations_' . (isset($this->instance->integrations[$integration->name]) ? 'enabled' : 'disabled')], show_alert: false ); - // Deleting the message buttons + // Reopening the integrations menu $this->integrations(robot: $robot); } @@ -1258,6 +1325,9 @@ final class create extends menu */ public function cost(telegram $robot): void { + // Sending the "typing" action + /* $robot->sendChatAction('typing'); */ + // Initializing the account language $language = $robot->get('language') ?? LANGUAGE_DEFAULT; @@ -1303,7 +1373,7 @@ final class create extends menu // Iterating over messages registry // Deleting the message - $message->delete(); + $message?->delete(); // Waiting just for rofls usleep(200); @@ -1327,7 +1397,7 @@ final class create extends menu "\n\n", array_filter( [ - "⚠️ $localization->project_create_cost_error_not_a_number", + "⚠️ $localization->project_cost_error_not_a_number", ] ) ), @@ -1348,7 +1418,7 @@ final class create extends menu array_filter( [ sprintf( - "⚠️ $localization->project_create_cost_error_distance", + "⚠️ $localization->project_cost_error_distance", $minimum, $maximum ) @@ -1372,14 +1442,14 @@ final class create extends menu "\n\n", array_filter( [ - "✏️ *$localization->project_create_cost_title*", - $localization->project_create_cost_description, + "✏️ *$localization->project_cost_title*", sprintf( - $localization->project_create_cost_default, - PROJECT_CREATE_COST_HOUR_DEFAULT, + $localization->project_cost_description, + PROJECT_COST_HOUR_DEFAULT, CURRENCY_DEFAULT->symbol() ?? '' ), - "⚠️ $localization->project_create_cost_warning" + $localization->project_cost_request, + "⚠️ $localization->project_cost_warning" ] ) ), @@ -1404,6 +1474,9 @@ final class create extends menu */ public function programmers(telegram $robot): void { + // Sending the "typing" action + /* $robot->sendChatAction('typing'); */ + // Initializing the account language $language = $robot->get('language') ?? LANGUAGE_DEFAULT; @@ -1419,37 +1492,34 @@ final class create extends menu // Initializing the message data $data = $robot->callbackQuery()?->data; - if (!empty($text) && $data !== 'set') { + if (!empty($text) || $text == '0' and $data !== 'set') { // Not empty text // Initializing the message filters - $minimum = 2; - $maximum = 5; + $minimum = PROJECT_WORKERS_PROGRAMMERS_MINIMUM; + $maximum = PROJECT_WORKERS_PROGRAMMERS_MAXIMUM; // Writing the user input message into the messages registry $this->messages[] = $message; - // Initializing the text length - $length = mb_strlen($text); + // Sanitizing + $int = filter_var($text, FILTER_SANITIZE_NUMBER_INT); - if ($length >= $minimum) { - // More than minimum amount of symbols + if (filter_var($int, FILTER_VALIDATE_INT) || $int == '0') { + // Number - // Sanitizing - $float = filter_var($text, FILTER_SANITIZE_NUMBER_FLOAT); - - if (filter_var($float, FILTER_VALIDATE_FLOAT)) { - // Number + if ($int >= $minimum and $int <= $maximum) { + // Not reached limits // Writing the cost - $this->cost = (float) $float; + $this->workers[worker_type::programmer->name] = (int) $int; try { foreach ($this->messages as $message) { // Iterating over messages registry // Deleting the message - $message->delete(); + $message?->delete(); // Waiting just for rofls usleep(200); @@ -1462,10 +1532,10 @@ final class create extends menu $this->messages = []; } - // Sending the process main menu - $this->continue(robot: $robot); + // Sending the process team menu + $this->team(robot: $robot); } else { - // Not a number + // Reached limits // Sending the message $this->messages[] = $robot->sendMessage( @@ -1473,7 +1543,10 @@ final class create extends menu "\n\n", array_filter( [ - "⚠️ $localization->project_create_cost_error_not_a_number", + sprintf( + "⚠️ $localization->project_team_programmers_error_amount", + $maximum + ) ] ) ), @@ -1482,10 +1555,10 @@ final class create extends menu ); // Waiting for the user input - $this->next('cost'); + $this->next('programmers'); } } else { - // Less or equal than minimum amount of symbols + // Not a number // Sending the message $this->messages[] = $robot->sendMessage( @@ -1493,11 +1566,7 @@ final class create extends menu "\n\n", array_filter( [ - sprintf( - "⚠️ $localization->project_create_cost_error_distance", - $minimum, - $maximum - ) + "⚠️ $localization->project_team_error_not_a_number", ] ) ), @@ -1506,7 +1575,7 @@ final class create extends menu ); // Waiting for the user input - $this->next('cost'); + $this->next('programmers'); } } else { // Empty text @@ -1518,14 +1587,9 @@ final class create extends menu "\n\n", array_filter( [ - "✏️ *$localization->project_create_cost_title*", - $localization->project_create_cost_description, - sprintf( - $localization->project_create_cost_default, - PROJECT_CREATE_COST_HOUR_DEFAULT, - CURRENCY_DEFAULT->symbol() ?? '' - ), - "⚠️ $localization->project_create_cost_warning" + "✏️ *$localization->project_team_programmers_title*", + $localization->project_team_programmers_description, + $localization->project_team_programmers_request ] ) ), @@ -1535,7 +1599,7 @@ final class create extends menu ]; // Waiting for the user input - $this->next('cost'); + $this->next('programmers'); } } @@ -1550,6 +1614,9 @@ final class create extends menu */ public function designers(telegram $robot): void { + // Sending the "typing" action + /* $robot->sendChatAction('typing'); */ + // Initializing the account language $language = $robot->get('language') ?? LANGUAGE_DEFAULT; @@ -1565,30 +1632,27 @@ final class create extends menu // Initializing the message data $data = $robot->callbackQuery()?->data; - if (!empty($text) && $data !== 'set') { + if (!empty($text) || $text == '0' and $data !== 'set') { // Not empty text // Initializing the message filters - $minimum = 2; - $maximum = 5; + $minimum = PROJECT_WORKERS_DESIGNERS_MINIMUM; + $maximum = PROJECT_WORKERS_DESIGNERS_MAXIMUM; // Writing the user input message into the messages registry $this->messages[] = $message; - // Initializing the text length - $length = mb_strlen($text); + // Sanitizing + $int = filter_var($text, FILTER_SANITIZE_NUMBER_INT); - if ($length >= $minimum) { - // More than minimum amount of symbols + if (filter_var($int, FILTER_VALIDATE_INT) || $int == '0') { + // Number - // Sanitizing - $float = filter_var($text, FILTER_SANITIZE_NUMBER_FLOAT); - - if (filter_var($float, FILTER_VALIDATE_FLOAT)) { - // Number + if ($int >= $minimum and $int <= $maximum) { + // Not reached limits // Writing the cost - $this->cost = (float) $float; + $this->workers[worker_type::designer->name] = (int) $int; try { foreach ($this->messages as $message) { @@ -1608,10 +1672,10 @@ final class create extends menu $this->messages = []; } - // Sending the process main menu - $this->continue(robot: $robot); + // Sending the process team menu + $this->team(robot: $robot); } else { - // Not a number + // Reached limits // Sending the message $this->messages[] = $robot->sendMessage( @@ -1619,7 +1683,10 @@ final class create extends menu "\n\n", array_filter( [ - "⚠️ $localization->project_create_cost_error_not_a_number", + sprintf( + "⚠️ $localization->project_team_designers_error_amount", + $maximum + ) ] ) ), @@ -1628,10 +1695,10 @@ final class create extends menu ); // Waiting for the user input - $this->next('cost'); + $this->next('designers'); } } else { - // Less or equal than minimum amount of symbols + // Not a number // Sending the message $this->messages[] = $robot->sendMessage( @@ -1639,11 +1706,7 @@ final class create extends menu "\n\n", array_filter( [ - sprintf( - "⚠️ $localization->project_create_cost_error_distance", - $minimum, - $maximum - ) + "⚠️ $localization->project_team_error_not_a_number", ] ) ), @@ -1652,7 +1715,7 @@ final class create extends menu ); // Waiting for the user input - $this->next('cost'); + $this->next('designers'); } } else { // Empty text @@ -1664,14 +1727,9 @@ final class create extends menu "\n\n", array_filter( [ - "✏️ *$localization->project_create_cost_title*", - $localization->project_create_cost_description, - sprintf( - $localization->project_create_cost_default, - PROJECT_CREATE_COST_HOUR_DEFAULT, - CURRENCY_DEFAULT->symbol() ?? '' - ), - "⚠️ $localization->project_create_cost_warning" + "✏️ *$localization->project_team_designers_title*", + $localization->project_team_designers_description, + $localization->project_team_designers_request, ] ) ), @@ -1681,7 +1739,7 @@ final class create extends menu ]; // Waiting for the user input - $this->next('cost'); + $this->next('designers'); } } @@ -1696,6 +1754,9 @@ final class create extends menu */ public function boosters(telegram $robot): void { + // Sending the "typing" action + /* $robot->sendChatAction('typing'); */ + // Initializing the account language $language = $robot->get('language') ?? LANGUAGE_DEFAULT; @@ -1711,37 +1772,34 @@ final class create extends menu // Initializing the message data $data = $robot->callbackQuery()?->data; - if (!empty($text) && $data !== 'set') { + if (!empty($text) || $text == '0' and $data !== 'set') { // Not empty text // Initializing the message filters - $minimum = 2; - $maximum = 5; + $minimum = PROJECT_WORKERS_BOOSTERS_MINIMUM; + $maximum = PROJECT_WORKERS_BOOSTERS_MAXIMUM; // Writing the user input message into the messages registry $this->messages[] = $message; - // Initializing the text length - $length = mb_strlen($text); + // Sanitizing + $int = filter_var($text, FILTER_SANITIZE_NUMBER_INT); - if ($length >= $minimum) { - // More than minimum amount of symbols + if (filter_var($int, FILTER_VALIDATE_INT) || $int == '0') { + // Number - // Sanitizing - $float = filter_var($text, FILTER_SANITIZE_NUMBER_FLOAT); - - if (filter_var($float, FILTER_VALIDATE_FLOAT)) { - // Number + if ($int >= $minimum and $int <= $maximum) { + // Not reached limits // Writing the cost - $this->cost = (float) $float; + $this->workers[worker_type::booster->name] = (int) $int; try { foreach ($this->messages as $message) { // Iterating over messages registry // Deleting the message - $message->delete(); + $message?->delete(); // Waiting just for rofls usleep(200); @@ -1754,10 +1812,10 @@ final class create extends menu $this->messages = []; } - // Sending the process main menu - $this->continue(robot: $robot); + // Sending the process team menu + $this->team(robot: $robot); } else { - // Not a number + // Reached limits // Sending the message $this->messages[] = $robot->sendMessage( @@ -1765,7 +1823,10 @@ final class create extends menu "\n\n", array_filter( [ - "⚠️ $localization->project_create_cost_error_not_a_number", + sprintf( + "⚠️ $localization->project_team_boosters_error_amount", + $maximum + ) ] ) ), @@ -1774,10 +1835,10 @@ final class create extends menu ); // Waiting for the user input - $this->next('cost'); + $this->next('boosters'); } } else { - // Less or equal than minimum amount of symbols + // Not a number // Sending the message $this->messages[] = $robot->sendMessage( @@ -1785,11 +1846,7 @@ final class create extends menu "\n\n", array_filter( [ - sprintf( - "⚠️ $localization->project_create_cost_error_distance", - $minimum, - $maximum - ) + "⚠️ $localization->project_team_error_not_a_number", ] ) ), @@ -1798,7 +1855,7 @@ final class create extends menu ); // Waiting for the user input - $this->next('cost'); + $this->next('boosters'); } } else { // Empty text @@ -1810,14 +1867,9 @@ final class create extends menu "\n\n", array_filter( [ - "✏️ *$localization->project_create_cost_title*", - $localization->project_create_cost_description, - sprintf( - $localization->project_create_cost_default, - PROJECT_CREATE_COST_HOUR_DEFAULT, - CURRENCY_DEFAULT->symbol() ?? '' - ), - "⚠️ $localization->project_create_cost_warning" + "✏️ *$localization->project_team_boosters_title*", + $localization->project_team_boosters_description, + $localization->project_team_boosters_request, ] ) ), @@ -1827,7 +1879,7 @@ final class create extends menu ]; // Waiting for the user input - $this->next('cost'); + $this->next('boosters'); } } @@ -1841,19 +1893,19 @@ final class create extends menu public function clear(): void { // Initializing the project architecture purposes - $purposes = $this->architecture->purposes(); + $purposes = $this->instance->architecture->purposes(); if (empty($purposes)) { // The project architecture has no purposes // Initializing the project purpose - $this->purpose = project_purpose::special; + $this->instance->purpose = project_purpose::special; } else if (count($purposes) === 1) { // The project architecture has only 1 purpose // Initializing the project purpose - $this->purpose = $purposes[0]; - } else if (isset($this->purpose) && array_search($this->purpose, $purposes) !== false) { + $this->instance->purpose = $purposes[0]; + } else if (isset($this->instance->purpose) && array_search($this->instance->purpose, $purposes) !== false) { // The project architecture purpose is the same from deprecated purpose // keep it @@ -1861,110 +1913,20 @@ final class create extends menu // The project can have other purposes // Deinitializing the deprecated project purpose - unset($this->purpose); + unset($this->instance->purpose); } // Deinitializing integrations - $this->integrations = []; - } + $this->instance->integrations = []; - /** - * Hours - * - * Calculate the project development hours - * - * @param bool $absolute Summary all coefficients and then multiply? - * - * @return int|float The project development hours - */ - public function hours(bool $absolute = false): int|float - { - // Initializing start hours - $start = PROJECT_CREATE_START_HOURS ?? 1; - $start < 1 and $start = 1; - - // Initializing additional hours - $additional = PROJECT_CREATE_HOURS_ADDITIONAL ?? 0; - - if ($absolute) { - // The absolute coefficient - - // Declaring coefficient - $coefficient = PROJECT_CREATE_START_COEFFICIENT ?? 0; - - if (isset($this->architecture)) { - // Initialized the project architecture - - // Adding into the coefficient - $coefficient += $this->architecture->coefficient() ?? 0; - } - - if (isset($this->purpose)) { - // Initialized the project purpose - - // Adding into the coefficient - $coefficient += $this->purpose->coefficient() ?? 0; - } - - if (!empty($this->integrations)) { - // Initialized the project integrations - - foreach ($this->integrations as $integration) { - // Iterating over the project integrations - - // Adding into the coefficient - $coefficient += $integration->coefficient() ?? 0; - } - } - - // Calculating the development hours - $hours = $start * $coefficient + $additional; - - // Calculating and exit (success) - return ceil(max($hours, PROJECT_CREATE_HOURS_MINIMAL)); - } else { - // The relative coefficient - - // Initializing the development hours - $hours = $start; - - if (isset($this->architecture)) { - // Initialized the project architecture - - // Adding into the coefficient - $hours *= $this->architecture->coefficient() ?? 1; - } - - if (isset($this->purpose)) { - // Initialized the project purpose - - // Adding into the coefficient - $hours *= $this->purpose->coefficient() ?? 1; - } - - if (!empty($this->integrations)) { - // Initialized the project integrations - - foreach ($this->integrations as $integration) { - // Iterating over the project integrations - - // Adding into the coefficient - $hours *= $integration->coefficient() ?? 1; - } - } - - // - $hours += $additional; - - // Calculating and exit (success) - return ceil(max($hours, PROJECT_CREATE_HOURS_MINIMAL)); - } + // Deinitializing workers + $this->workers = []; } /** * Request * - * + * Create the project and send it into operators chats * * @param telegram $robot The robot * @@ -1972,39 +1934,102 @@ final class create extends menu */ public function request(telegram $robot): void { + // Sending the "typing" action + /* $robot->sendChatAction('typing'); */ + // Initializing the account language $language = $robot->get('language') ?? LANGUAGE_DEFAULT; // Initializing the account localization $localization = $robot->get('localization') ?? new localization($language); + // Initializing the account + $account = $robot->get('account'); + // Initializing the receivers registry - $receivers = PROJECT_CREATE_REQUEST_RECEIVERS; + $receivers = DEALS_RECEIVERS; // Architecture - $architecture = unmarkdown($this->architecture?->label(language: $language) ?? $localization->project_request_empty); + $architecture = unmarkdown($this->instance->architecture?->label(language: $language) ?? $localization->project_deal_empty); // Purpose - $purpose = unmarkdown(isset($this->purpose) ? $this->purpose->label(language: $language) : $localization->project_request_empty); + $purpose = unmarkdown(isset($this->instance->purpose) ? $this->instance->purpose->label(language: $language) : $localization->project_deal_empty); // Hours - $hours = $this->hours(); + $hours = $this->instance->hours(); - // P + // Project + $project = <<project_deal_architecture:* $architecture + *$localization->project_deal_purpose:* $purpose + TXT; + + // Days + $days = ceil(($hours / PROJECT_DAY_HOURS) + PROJECT_DAY_ADDITIONAL); + + // Time + $time = "*$localization->project_deal_time:* $hours$localization->project_deal_time_hours _\($days$localization->project_deal_time_days\)_"; + + // Calculating the project development costs + $costs = $this->instance->payment( + cost: $this->cost, + hours: $hours, + programmers: $this->workers[worker_type::programmer->name] ?? 0, + designers: $this->designers[worker_type::designer->name] ?? 0, + boosters: $this->boosters[worker_type::booster->name] ?? 0 + ); + + // Creating the deal + $deal = new deal()->write( + account: $account->identifier, + project: $this->instance->identifier, + direction: deal_direction::outbound, + description: $this->description, + hours: $hours, + cost: $this->cost, + payment: $costs['full'], + prepayment: $costs['prepayment'], + programmers: $this->workers[worker_type::programmer->name] ?? 0, + designers: $this->workers[worker_type::designer->name] ?? 0, + boosters: $this->workers[worker_type::booster->name] ?? 0, + ); + + // Title + $title = '*' . unmarkdown(sprintf("💸 $localization->project_deal_title", $deal->identifier)) . '*'; + + // Payment + $payment = []; + + // Writing the project create message full cost + $payment['full'] = "*$localization->project_cost:* " . $costs['full'] . $account->currency->symbol(); + + // Writing the project create message cost prepayment + $payment['prepayment'] = "*$localization->project_cost_prepayment:* " . $costs['prepayment'] . $account->currency->symbol() . ' _\(' . PROJECT_COST_PREPAYMENT_PERCENTS . '%\)_'; + + // Writing the project status + $this->instance->status = project_status::requested; + + // Serializing the project record + $this->instance->serialize(); + + // Updating the project record + $this->instance->update(); + + // Deserializing the project record + $this->instance->deserialize(); // Generating the message text $text = implode( "\n\n", array_filter( [ - '*' . unmarkdown(sprintf("💸 $localization->project_request_title", $sex ?? 0)) . '*', - <<project_request_architecture:* $architecture - *$localization->project_request_purpose:* $purpose - TXT, - <<project_request_hours:* $hours - TXT + $title, + $project, + $time, + implode( + "\n", + $payment + ) ] ) ); @@ -2015,7 +2040,7 @@ final class create extends menu // Writing the row into the keyboard $keyboard->addRow( button::make( - text: "✉️ $localization->project_request_button_chat", + text: "✉️ $localization->project_deal_button_chat", url: 'https://t.me/' . $robot->user()->username ) ); @@ -2023,24 +2048,24 @@ final class create extends menu // Writing the row into the keyboard $keyboard->addRow( button::make( - text: "⚖️ $localization->project_request_button_edit", - callback_data: 'edit' + text: "⚖️ $localization->project_deal_button_edit", + callback_data: 'project_deal_edit' ) ); // Writing the row into the keyboard $keyboard->addRow( button::make( - text: "✅ $localization->project_request_button_accept", - callback_data: 'accept' + text: "❌ $localization->project_deal_button_refuse", + callback_data: 'project_deal_decline' ), button::make( - text: "❌ $localization->project_request_button_refuse", - callback_data: 'refuse' + text: "✅ $localization->project_deal_button_accept", + callback_data: 'project_deal_accept' ) ); - foreach ($receivers as $index => $receiver) { + foreach ($receivers as $receiver) { // Iterating over receivers // Sending the message @@ -2055,7 +2080,7 @@ final class create extends menu // Sending the message $robot->sendMessage( - text: "✅ *$localization->project_create_requested*", + text: "✅ *$localization->project_deal_requested*", parse_mode: mode::MARKDOWN, disable_notification: true ); @@ -2075,6 +2100,9 @@ final class create extends menu */ public function stop(telegram $robot): void { + // Sending the "typing" action + /* $robot->sendChatAction('typing'); */ + // Initializing the account language $language = $robot->get('language') ?? LANGUAGE_DEFAULT; @@ -2083,7 +2111,7 @@ final class create extends menu // Sending the message $robot->sendMessage( - text: "⚠️ *$localization->project_create_cancelled*", + text: "⚠️ *$localization->project_cancelled*", parse_mode: mode::MARKDOWN, disable_notification: true ); @@ -2091,4 +2119,121 @@ final class create extends menu // Ending the conversation $this->end(); } + + /** + * Accept + * + * Accept the project and issue an invoice + * + * @param telegram $robot The robot + * + * @return void + */ + public function project_create_accept(telegram $robot): void + { + error_log($robot->callbackQuery()->data); + return; + // Sending the "typing" action + /* $robot->sendChatAction('typing'); */ + + // Initializing the account language + $language = $robot->get('language') ?? LANGUAGE_DEFAULT; + + // Initializing the account localization + $localization = $robot->get('localization') ?? new localization($language); + + // Initializing the account + $account = $robot->get('account'); + + // Initializing the account authorizations + $authorizations = $account->authorizations(); + + if ($authorizations->system_projects) { + // Authorized to projects (system) + + if ($authorizations->system_invoices) { + // Authorized to projects (system) + + // Initializing the keyboard + $keyboard = keyboard::make(); + + // Writing the row into the keyboard + $keyboard->addRow( + button::make( + text: "🔏 $localization->project_accepted_button_prepayment", + url: 'https://t.me/' . $robot->user()->username + ) + ); + + // Initializing the project development hours + $hours = $this->instance->hours(); + + // Initializing the project development costs + $costs = $this->instance->payment( + cost: $this->cost, + hours: $hours, + programmers: $this->workers[worker_type::programmer->name] ?? 0, + designers: $this->designers[worker_type::designer->name] ?? 0, + boosters: $this->boosters[worker_type::booster->name] ?? 0 + ); + + // Initializing the receiver account + $receiver = new account()->read(filter: fn(record $record) => $record->identifier === $this->instance->account); + + // Title + $title = "🏗 *$localization->project_accepted_title*"; + + // Description + $description = $localization->project_accepted_description; + + // Prepayment + $prepayment = "*$localization->project_accepted_prepayment:* " . $costs['prepayment'] . $receiver->currency->symbol() . ' _\(' . PROJECT_COST_PREPAYMENT_PERCENTS . '%\)_'; + + // Documents + $documents = $localization->project_accepted_documents; + + // Sending the message + $robot->sendMessage( + text: implode( + "\n\n", + array_filter([ + $title, + $description, + $prepayment, + $documents + ]) + ), + chat_id: $receiver->telegram_identifier, + parse_mode: mode::MARKDOWN, + disable_notification: true, + reply_markup: $keyboard + ); + + // Ending the conversation + $this->end(); + } else { + // Not authorized to projects (system) + + // Sending the message + $robot->sendMessage( + text: "⛔ *$localization->not_authorized_system_invoices*", + parse_mode: mode::MARKDOWN, + ); + + // Ending the conversation + $robot->endConversation(); + } + } else { + // Not authorized to projects (system) + + // Sending the message + $robot->sendMessage( + text: "⛔ *$localization->not_authorized_system_projects*", + parse_mode: mode::MARKDOWN, + ); + + // Ending the conversation + $robot->endConversation(); + } + } } diff --git a/kodorvan/constructor/system/models/telegram/exceptions.php b/kodorvan/constructor/system/models/telegram/exceptions.php new file mode 100644 index 0000000..4aa4ddc --- /dev/null +++ b/kodorvan/constructor/system/models/telegram/exceptions.php @@ -0,0 +1,48 @@ + + * + * @deprecated + */ +final class exceptions extends telegram_api_exception +{ + public static ?string $pattern = '.*'; + + public function __invoke(telegram $robot, telegram_exception $exception) + { + // override this method to change the default behaviour: + $robot->sendMessage('robot zdox'); + throw new static($exception->getMessage(), $exception->getCode(), $exception); + } +} diff --git a/kodorvan/constructor/system/models/telegram/project.php b/kodorvan/constructor/system/models/telegram/project.php index 5c9e030..7826aae 100644 --- a/kodorvan/constructor/system/models/telegram/project.php +++ b/kodorvan/constructor/system/models/telegram/project.php @@ -8,8 +8,13 @@ namespace kodorvan\constructor\models\telegram; use kodorvan\constructor\models\core, kodorvan\constructor\models\account, kodorvan\constructor\models\localization, - kodorvan\constructor\models\settings as model, - kodorvan\constructor\models\telegram\processes\language\select as process_language_select; + kodorvan\constructor\models\settings, + kodorvan\constructor\models\deal, + kodorvan\constructor\models\project as model, + kodorvan\constructor\models\project\enumerations\status as project_status, + kodorvan\constructor\models\worker\enumerations\type as worker_type, + kodorvan\constructor\models\telegram\processes\language\select as process_language_select, + kodorvan\constructor\models\telegram\conversations\project as conversation_project; // Library for languages support use mirzaev\languages\language; @@ -17,6 +22,16 @@ use mirzaev\languages\language; // The library for escaping all markdown symbols use function mirzaev\unmarkdown; +// Svoboda time +use svoboda\time\statement as svoboda; + +// Baza database +use mirzaev\baza\database, + mirzaev\baza\column, + mirzaev\baza\record, + mirzaev\baza\enumerations\encoding, + mirzaev\baza\enumerations\type; + // Framework for Telegram use SergiX44\Nutgram\Nutgram as telegram, SergiX44\Nutgram\Telegram\Properties\ParseMode as mode, @@ -27,7 +42,8 @@ use SergiX44\Nutgram\Nutgram as telegram, SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardButton as button; // Built-in libraries -use Error as error; +use DateTime as datetime, + Error as error; /** * Telegram project @@ -40,42 +56,260 @@ use Error as error; final class project extends core { /** - * Language + * Create * - * Write the language into the account and the robot instance + * Starting the project creating process * * @param telegram $robot The chat-robot instance - * @param language $language The language * * @return void */ - public static function create(telegram $robot, language $language = LANGUAGE_DEFAULT): void + public static function create(telegram $robot): void { - /* // Initializing the account + // Initializing the account $account = $robot->get('account'); - if ($account instanceof account) { - // Initialized the account + // Initializing the project record + $record = new model()->write(account: $account->identifier); - // Initializing the menu message localization - $localization = new localization($language); + // Initializing the project + $project = new model(record: $record); - if ($localization instanceof localization) { - // Initialized the localization + // Deserializing the record + $project->deserialize(); + + // Starting the project creating process + conversation_project::begin( + bot: $robot, + userId: $robot->userId(), + chatId: $robot->chatId(), + data: ['instance' => $project] + ); + } + + /** + * Accept + * + * Accept the project and issue an invoice + * + * @param telegram $robot The robot + * + * @return void + */ + public function accept(telegram $robot): void + { + // Sending the "typing" action + /* $robot->sendChatAction('typing'); */ + + // Initializing the account language + $language = $robot->get('language') ?? LANGUAGE_DEFAULT; + + // Initializing the account localization + $localization = $robot->get('localization') ?? new localization($language); + + // Initializing the account + $account = $robot->get('account'); + + // Initializing the account authorizations + $authorizations = $account->authorizations(); + + if ($authorizations->system_deals) { + // Authorized to deals (system) + + if ($authorizations->system_projects) { + // Authorized to projects (system) + + if ($authorizations->system_invoices) { + // Authorized to invoices (system) + + // The message + $message = $robot->message(); + + // The message text + $text = $message?->text; + + // The project identifier + preg_match('/^.*#(\d+)$/m', $text, $matches); + $identifier = (int) $matches[1]; + unset($matches); + + // The deal + $deal = new deal()->read(filter: fn(record $record) => $record->identifier === $identifier && $record->active === 1); + + // Deserializing the record + $deal->deserialize(); + + if ($deal instanceof deal) { + // Initialized the deal + + // The project + $project = $deal->project(); + + if ($project instanceof model) { + // Initialized the project + + if ($project->status === project_status::requested && $deal->confirmed === 0) { + // The project deal is not confirmed + + // Initializing the keyboard + $keyboard = keyboard::make(); + + // Writing the row into the keyboard + $keyboard->addRow( + button::make( + text: "🔏 $localization->project_accepted_button_prepayment", + url: 'https://t.me/' . $robot->user()->username + ) + ); + + // Initializing the receiver account + $receiver = $project->account(); + + // Title + $title = "🏗 *$localization->project_accepted_title*"; + + // Description + $description = $localization->project_accepted_description; + + // Prepayment + $prepayment = "*$localization->project_accepted_prepayment:* $deal->prepayment" . $receiver->currency->symbol(); + + // Documents + $documents = $localization->project_accepted_documents; + + // Sending the message + $robot->sendMessage( + text: implode( + "\n\n", + array_filter([ + $title, + $description, + $documents, + $prepayment + ]) + ), + chat_id: $receiver->identifier_telegram, + parse_mode: mode::MARKDOWN, + disable_notification: true, + reply_markup: $keyboard + ); + + // Ending the conversation + $robot->endConversation(); + + // Writing the confirmation date + $deal->confirmed = svoboda::timestamp(); + + // Serializing the record + $deal->serialize(); + + // Updating the deal record + $deal->update(); + + // Deserializing the record + $deal->deserialize(); + + // Initializing the keyboard + $keyboard = keyboard::make(); + + // Writing the row into the keyboard + $keyboard->addRow( + button::make( + text: "✉️ $localization->project_deal_button_chat", + url: 'https://t.me/' . $robot->user()->username + ) + ); + + // Converting the confirmation to unixtime format + $unixtime = $deal->confirmed + svoboda::datetime()->getTimestamp(); + + // Confirmed + /* $confirmed = "*$localization->project_accepted_confirmed*: ![" . $unixtime . '](tg://time?unix=' . $unixtime . '&format=r)'; */ + $confirmed = "$localization->project_accepted_confirmed: ![" . $unixtime . '](tg://time?unix=' . $unixtime . '&format=r)'; + + // Updating the message buttons + $message->editText( + text: implode( + "\n\n", + [ + $message->getText(), + $confirmed + ] + ), + /* parse_mode: mode::MARKDOWN, */ + reply_markup: $keyboard + ); + } else { + // The project deal is confirmed + + // Sending the message + $robot->sendMessage( + text: "⚠️ *$localization->project_accepted_already_confirmed*", + parse_mode: mode::MARKDOWN, + ); + + // Ending the conversation + $robot->endConversation(); + } + } else { + // Not initialized the project + + // Sending the message + $robot->sendMessage( + text: "⚠️ *$localization->project_accepted_project_not_found*", + parse_mode: mode::MARKDOWN, + ); + + // Ending the conversation + $robot->endConversation(); + } + } else { + // Not initialized the project + + // Sending the message + $robot->sendMessage( + text: "⚠️ *$localization->project_accepted_deal_not_found*", + parse_mode: mode::MARKDOWN, + ); + + // Ending the conversation + $robot->endConversation(); + } + } else { + // Not authorized to invoices (system) + + // Sending the message + $robot->sendMessage( + text: "⛔ *$localization->not_authorized_system_invoices*", + parse_mode: mode::MARKDOWN, + ); + + // Ending the conversation + $robot->endConversation(); + } + } else { + // Not authorized to projects (system) // Sending the message $robot->sendMessage( - text: "✅ *$localization->settings_language_update_success:* " . trim($from->flag() . ' ' . $from->label($to)) . ' → *' . trim($to->flag() . ' ' . $to->label($to)) . '*', + text: "⛔ *$localization->not_authorized_system_projects*", parse_mode: mode::MARKDOWN, - disable_notification: true ); - // Sending the message - $robot->answerCallbackQuery( - text: $to->label($to), - show_alert: false - ); + // Ending the conversation + $robot->endConversation(); } - } */ + } else { + // Not authorized to deals (system) + + // Sending the message + $robot->sendMessage( + text: "⛔ *$localization->not_authorized_system_deals*", + parse_mode: mode::MARKDOWN, + ); + + // Ending the conversation + $robot->endConversation(); + } } } diff --git a/kodorvan/constructor/system/public/index.php b/kodorvan/constructor/system/public/index.php deleted file mode 100644 index 7a709c9..0000000 --- a/kodorvan/constructor/system/public/index.php +++ /dev/null @@ -1,52 +0,0 @@ -router - ->write('/', new route('index', 'index'), 'GET') -; - -// Handling request -$core->start(); diff --git a/kodorvan/constructor/system/public/telegram/constructor/webhook.php b/kodorvan/constructor/system/public/telegram/constructor/webhook.php index 6cb6868..33144a4 100644 --- a/kodorvan/constructor/system/public/telegram/constructor/webhook.php +++ b/kodorvan/constructor/system/public/telegram/constructor/webhook.php @@ -6,12 +6,14 @@ namespace kodorvan\constructor; // Files of the project use kodorvan\constructor\models\account, - kodorvan\constructor\models\telegram\settings, + kodorvan\constructor\models\localization, + kodorvan\constructor\models\telegram\settings as telegram_settings, + kodorvan\constructor\models\telegram\project as telegram_project, kodorvan\constructor\models\telegram\commands\start as command_start, kodorvan\constructor\models\telegram\commands\account as command_account, kodorvan\constructor\models\telegram\commands\society as command_society, kodorvan\constructor\models\telegram\commands\language as command_language, - kodorvan\constructor\models\telegram\conversations\project\create as conversation_project_create, + /* kodorvan\constructor\models\telegram\conversations\project\create as conversation_project_create, */ kodorvan\constructor\models\telegram\middlewares\account as middleware_account, kodorvan\constructor\models\telegram\middlewares\language as middleware_language, kodorvan\constructor\models\telegram\middlewares\localization as middleware_localization, @@ -25,15 +27,25 @@ use mirzaev\languages\language; use mirzaev\minimal\core, mirzaev\minimal\route; +// The library for escaping all markdown symbols +use function mirzaev\unmarkdown; + // Framework for Telegram -use SergiX44\Nutgram\Nutgram as telegram, - SergiX44\Nutgram\Configuration as telegram_settings, - SergiX44\Nutgram\RunningMode\Webhook as webhook; +use SergiX44\Nutgram\Nutgram as framework_telegram, + SergiX44\Nutgram\Configuration as framework_telegram_settings, + SergiX44\Nutgram\RunningMode\Webhook as framework_telegram_webhook, + SergiX44\Nutgram\Telegram\Properties\ParseMode as mode, + SergiX44\Nutgram\Telegram\Exceptions\TelegramException as framework_telegram_exception, + SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardMarkup as keyboard, + SergiX44\Nutgram\Telegram\Types\Keyboard\InlineKeyboardButton as button; // The symphony cache library use Symfony\Component\Cache\Adapter\FilesystemAdapter as cache_adapter, Symfony\Component\Cache\Psr16Cache as cache; +// Built-in libraries +use Exception as exception; + // Enabling debugging /* ini_set('error_reporting', E_ALL); ini_set('display_errors', 1); @@ -70,18 +82,19 @@ define('TELEGRAM', require(SETTINGS . DIRECTORY_SEPARATOR . 'telegram.php')); require ROOT . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php'; // Initializing the robot -$robot = new telegram( +$robot = new framework_telegram( token: TELEGRAM['key'], - config: new telegram_settings( + config: new framework_telegram_settings( botName: TELEGRAM['name'], cache: new cache(new cache_adapter()) ) ); -$webhook = new webhook(secretToken: TELEGRAM['password']); +$webhook = new framework_telegram_webhook(secretToken: TELEGRAM['password']); $webhook->setSafeMode(true); $robot->setRunningMode($webhook); +$robot->throttle(10); $robot->middleware(middleware_account::class); $robot->middleware(middleware_language::class); @@ -103,13 +116,108 @@ foreach (language::cases() as $language) { // Iterating over languages // Select the language - $robot->onCallbackQueryData('settings_language_$language->name', fn(telegram $robot) => settings::language(robot: $robot, language: $language)); + $robot->onCallbackQueryData('settings_language_$language->name', fn(framework_telegram $robot) => telegram_settings::language(robot: $robot, language: $language)); }; // Society $robot->registerCommand(command_society::class); // Project: create -$robot->onCallbackQueryData('project_create', conversation_project_create::class); +$robot->onCallbackQueryData('project_create', [telegram_project::class, 'create']); -$robot->run(); +// Project: request +$robot + ->onCallbackQueryData('project_deal_accept', [telegram_project::class, 'accept']); + +$robot->onApiError(function (framework_telegram $robot, framework_telegram_exception $exception) { + try { + // Writing into the errors output + error_log($exception->getMessage()); + + // Initializing the account language + $language = $robot->get('language') ?? LANGUAGE_DEFAULT; + + // Initializing the account localization + $localization = $robot->get('localization') ?? new localization($language); + + // Initializing the keyboard + $keyboard = keyboard::make(); + + // Writing the row into the keyboard + $keyboard->addRow( + button::make( + text: "✉️ $localization->error_button_chat_operator", + url: PROJECT_OPERATOR_URL ?? PROJECT_MEDIA_URL ?? 'https://t.me/kodorvan' + ) + ); + + // Title + $title = "🔥 *$localization->error_title*"; + + // Description + $description = $localization->error_description; + + // Repeat + $repeat = $localization->error_repeat; + + // Sending the message + $robot->sendMessage( + text: implode( + "\n\n", + [ + $title, + $description, + $repeat + ] + ), + disable_notification: true, + parse_mode: mode::MARKDOWN, + reply_markup: $keyboard + ); + + // Ending the conversation + $robot->endConversation(); + + foreach (ERRORS_RECEIVERS as $receiver) { + // Iterating over errors receivers + + // Initializing the keyboard + $keyboard = keyboard::make(); + + // Writing the row into the keyboard + $keyboard->addRow( + button::make( + text: "✉️ $localization->error_button_chat_user", + url: 'https://t.me/' . $robot->user()->username + ) + ); + + // Domain + /* $domain = "*$localization->error_account:* @" . $robot->user()->username; */ + + // Sending the message + $robot->sendMessage( + text: implode( + "\n\n", + [ + $exception->getMessage(), + /* $domain */ + ] + ), + chat_id: $receiver, + /* parse_mode: mode::MARKDOWN, */ + reply_markup: $keyboard + ); + } + } catch (exception $exception) { + // Writing into the errors output + error_log($exception->getMessage()); + } +}); + +try { + $robot->run(); +} catch (exception $exception) { + // Writing into the errors output + error_log($exception->getMessage()); +}