diff --git a/.env.dist b/.env.dist
index eeafa62..28137cc 100644
--- a/.env.dist
+++ b/.env.dist
@@ -7,3 +7,16 @@ MYSQL_VERSION=8.0.27
MYSQL_DATABASE=databasorus
MYSQL_USER=user
MYSQL_PASSWORD=password
+
+###> symfony/messenger ###
+# Choose one of the transports below
+# MESSENGER_TRANSPORT_DSN=doctrine://default
+# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
+# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
+###< symfony/messenger ###
+
+###> symfony/lock ###
+# Choose one of the stores below
+# postgresql+advisory://db_user:db_password@localhost/db_name
+LOCK_DSN=flock
+###< symfony/lock ###
diff --git a/Makefile b/Makefile
index 0ef82db..d12b2af 100644
--- a/Makefile
+++ b/Makefile
@@ -32,3 +32,8 @@ fixtures-load:
.PHONY: reset-db
reset-db: database-drop database-create database-migrate fixtures-load
+ docker compose run --rm php bin/console doctrine:fixtures:load
+
+.PHONY: worker
+worker:
+ docker compose run --rm php bin/console messenger:consume async -vv
diff --git a/composer.json b/composer.json
index f760f5c..8a99cf2 100644
--- a/composer.json
+++ b/composer.json
@@ -11,9 +11,11 @@
"doctrine/doctrine-bundle": "^2.12",
"doctrine/doctrine-migrations-bundle": "^3.3",
"doctrine/orm": "^3.1",
+ "elasticsearch/elasticsearch": "^8.6",
"phpdocumentor/reflection-docblock": "^5.4",
"symfony/asset": "^7.0",
"symfony/console": "^7.0",
+ "symfony/doctrine-messenger": "^7.0",
"symfony/dotenv": "^7.0",
"symfony/expression-language": "^7.0",
"symfony/flex": "^2.4.5",
@@ -21,7 +23,9 @@
"symfony/framework-bundle": "^7.0",
"symfony/http-client": "^7.0",
"symfony/intl": "^7.0",
+ "symfony/lock": "^7.0",
"symfony/mailer": "^7.0",
+ "symfony/messenger": "^7.0",
"symfony/mime": "^7.0",
"symfony/monolog-bundle": "^3.10",
"symfony/notifier": "^7.0",
@@ -54,7 +58,8 @@
},
"config": {
"allow-plugins": {
- "symfony/*": true
+ "symfony/*": true,
+ "php-http/discovery": true
},
"optimize-autoloader": true,
"preferred-install": {
diff --git a/composer.lock b/composer.lock
index a3c72ad..2c574d8 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "e1d68fda857d3a6a99a9c9d4e0c1c4dd",
+ "content-hash": "a5b6857e351b48ef5e0f02910f02413b",
"packages": [
{
"name": "composer/package-versions-deprecated",
@@ -174,16 +174,16 @@
},
{
"name": "doctrine/collections",
- "version": "2.2.1",
+ "version": "2.2.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/collections.git",
- "reference": "420480fc085bc65f3c956af13abe8e7546f94813"
+ "reference": "d8af7f248c74f195f7347424600fd9e17b57af59"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/collections/zipball/420480fc085bc65f3c956af13abe8e7546f94813",
- "reference": "420480fc085bc65f3c956af13abe8e7546f94813",
+ "url": "https://api.github.com/repos/doctrine/collections/zipball/d8af7f248c74f195f7347424600fd9e17b57af59",
+ "reference": "d8af7f248c74f195f7347424600fd9e17b57af59",
"shasum": ""
},
"require": {
@@ -240,7 +240,7 @@
],
"support": {
"issues": "https://github.com/doctrine/collections/issues",
- "source": "https://github.com/doctrine/collections/tree/2.2.1"
+ "source": "https://github.com/doctrine/collections/tree/2.2.2"
},
"funding": [
{
@@ -256,20 +256,20 @@
"type": "tidelift"
}
],
- "time": "2024-03-05T22:28:45+00:00"
+ "time": "2024-04-18T06:56:21+00:00"
},
{
"name": "doctrine/dbal",
- "version": "4.0.1",
+ "version": "4.0.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
- "reference": "9e588fe1f38a443cb17de6b86b803d9e028e2156"
+ "reference": "61d79c6e379a39dc1fea6b4e50a23dfc3cd2076a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/dbal/zipball/9e588fe1f38a443cb17de6b86b803d9e028e2156",
- "reference": "9e588fe1f38a443cb17de6b86b803d9e028e2156",
+ "url": "https://api.github.com/repos/doctrine/dbal/zipball/61d79c6e379a39dc1fea6b4e50a23dfc3cd2076a",
+ "reference": "61d79c6e379a39dc1fea6b4e50a23dfc3cd2076a",
"shasum": ""
},
"require": {
@@ -348,7 +348,7 @@
],
"support": {
"issues": "https://github.com/doctrine/dbal/issues",
- "source": "https://github.com/doctrine/dbal/tree/4.0.1"
+ "source": "https://github.com/doctrine/dbal/tree/4.0.2"
},
"funding": [
{
@@ -364,7 +364,7 @@
"type": "tidelift"
}
],
- "time": "2024-03-03T15:59:11+00:00"
+ "time": "2024-04-25T08:29:52+00:00"
},
{
"name": "doctrine/deprecations",
@@ -1057,16 +1057,16 @@
},
{
"name": "doctrine/orm",
- "version": "3.1.1",
+ "version": "3.1.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/orm.git",
- "reference": "9c560713925ac5859342e6ff370c4c997acf2fd4"
+ "reference": "f79d166a4e844beb9389f23bdb44abdbf58cec38"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/orm/zipball/9c560713925ac5859342e6ff370c4c997acf2fd4",
- "reference": "9c560713925ac5859342e6ff370c4c997acf2fd4",
+ "url": "https://api.github.com/repos/doctrine/orm/zipball/f79d166a4e844beb9389f23bdb44abdbf58cec38",
+ "reference": "f79d166a4e844beb9389f23bdb44abdbf58cec38",
"shasum": ""
},
"require": {
@@ -1139,9 +1139,9 @@
],
"support": {
"issues": "https://github.com/doctrine/orm/issues",
- "source": "https://github.com/doctrine/orm/tree/3.1.1"
+ "source": "https://github.com/doctrine/orm/tree/3.1.2"
},
- "time": "2024-03-21T11:37:52+00:00"
+ "time": "2024-04-15T14:20:40+00:00"
},
{
"name": "doctrine/persistence",
@@ -1360,6 +1360,119 @@
],
"time": "2023-10-06T06:47:41+00:00"
},
+ {
+ "name": "elastic/transport",
+ "version": "v8.8.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/elastic/elastic-transport-php.git",
+ "reference": "cdf9f63a16ec6bfb4c881ab89aa0e2a61fb7c20b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/elastic/elastic-transport-php/zipball/cdf9f63a16ec6bfb4c881ab89aa0e2a61fb7c20b",
+ "reference": "cdf9f63a16ec6bfb4c881ab89aa0e2a61fb7c20b",
+ "shasum": ""
+ },
+ "require": {
+ "composer-runtime-api": "^2.0",
+ "php": "^7.4 || ^8.0",
+ "php-http/discovery": "^1.14",
+ "php-http/httplug": "^2.3",
+ "psr/http-client": "^1.0",
+ "psr/http-factory": "^1.0",
+ "psr/http-message": "^1.0 || ^2.0",
+ "psr/log": "^1 || ^2 || ^3"
+ },
+ "require-dev": {
+ "nyholm/psr7": "^1.5",
+ "php-http/mock-client": "^1.5",
+ "phpstan/phpstan": "^1.4",
+ "phpunit/phpunit": "^9.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Elastic\\Transport\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "HTTP transport PHP library for Elastic products",
+ "keywords": [
+ "PSR_17",
+ "elastic",
+ "http",
+ "psr-18",
+ "psr-7",
+ "transport"
+ ],
+ "support": {
+ "issues": "https://github.com/elastic/elastic-transport-php/issues",
+ "source": "https://github.com/elastic/elastic-transport-php/tree/v8.8.0"
+ },
+ "time": "2023-11-08T10:51:51+00:00"
+ },
+ {
+ "name": "elasticsearch/elasticsearch",
+ "version": "v8.13.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/elastic/elasticsearch-php.git",
+ "reference": "221723e9497515ec82833995a97c8546d9b6499a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/elastic/elasticsearch-php/zipball/221723e9497515ec82833995a97c8546d9b6499a",
+ "reference": "221723e9497515ec82833995a97c8546d9b6499a",
+ "shasum": ""
+ },
+ "require": {
+ "elastic/transport": "^8.8",
+ "guzzlehttp/guzzle": "^7.0",
+ "php": "^7.4 || ^8.0",
+ "psr/http-client": "^1.0",
+ "psr/http-message": "^1.1 || ^2.0",
+ "psr/log": "^1|^2|^3"
+ },
+ "require-dev": {
+ "ext-yaml": "*",
+ "ext-zip": "*",
+ "mockery/mockery": "^1.5",
+ "nyholm/psr7": "^1.5",
+ "php-http/message-factory": "^1.0",
+ "php-http/mock-client": "^1.5",
+ "phpstan/phpstan": "^1.4",
+ "phpunit/phpunit": "^9.5",
+ "psr/http-factory": "^1.0",
+ "symfony/finder": "~4.0",
+ "symfony/http-client": "^5.0|^6.0|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Elastic\\Elasticsearch\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "PHP Client for Elasticsearch",
+ "keywords": [
+ "client",
+ "elastic",
+ "elasticsearch",
+ "search"
+ ],
+ "support": {
+ "issues": "https://github.com/elastic/elasticsearch-php/issues",
+ "source": "https://github.com/elastic/elasticsearch-php/tree/v8.13.0"
+ },
+ "time": "2024-03-27T15:09:06+00:00"
+ },
{
"name": "friendsofphp/proxy-manager-lts",
"version": "v1.0.18",
@@ -1442,6 +1555,331 @@
],
"time": "2024-03-20T12:50:41+00:00"
},
+ {
+ "name": "guzzlehttp/guzzle",
+ "version": "7.8.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/guzzle.git",
+ "reference": "41042bc7ab002487b876a0683fc8dce04ddce104"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104",
+ "reference": "41042bc7ab002487b876a0683fc8dce04ddce104",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "guzzlehttp/promises": "^1.5.3 || ^2.0.1",
+ "guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
+ "php": "^7.2.5 || ^8.0",
+ "psr/http-client": "^1.0",
+ "symfony/deprecation-contracts": "^2.2 || ^3.0"
+ },
+ "provide": {
+ "psr/http-client-implementation": "1.0"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.8.2",
+ "ext-curl": "*",
+ "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
+ "php-http/message-factory": "^1.1",
+ "phpunit/phpunit": "^8.5.36 || ^9.6.15",
+ "psr/log": "^1.1 || ^2.0 || ^3.0"
+ },
+ "suggest": {
+ "ext-curl": "Required for CURL handler support",
+ "ext-intl": "Required for Internationalized Domain Name (IDN) support",
+ "psr/log": "Required for using the Log middleware"
+ },
+ "type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": false
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "GuzzleHttp\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Jeremy Lindblom",
+ "email": "jeremeamia@gmail.com",
+ "homepage": "https://github.com/jeremeamia"
+ },
+ {
+ "name": "George Mponos",
+ "email": "gmponos@gmail.com",
+ "homepage": "https://github.com/gmponos"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://github.com/sagikazarmark"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "Guzzle is a PHP HTTP client library",
+ "keywords": [
+ "client",
+ "curl",
+ "framework",
+ "http",
+ "http client",
+ "psr-18",
+ "psr-7",
+ "rest",
+ "web service"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/guzzle/issues",
+ "source": "https://github.com/guzzle/guzzle/tree/7.8.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-12-03T20:35:24+00:00"
+ },
+ {
+ "name": "guzzlehttp/promises",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/promises.git",
+ "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223",
+ "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5 || ^8.0"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.8.2",
+ "phpunit/phpunit": "^8.5.36 || ^9.6.15"
+ },
+ "type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": false
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Promise\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "Guzzle promises library",
+ "keywords": [
+ "promise"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/promises/issues",
+ "source": "https://github.com/guzzle/promises/tree/2.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-12-03T20:19:20+00:00"
+ },
+ {
+ "name": "guzzlehttp/psr7",
+ "version": "2.6.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/psr7.git",
+ "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221",
+ "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5 || ^8.0",
+ "psr/http-factory": "^1.0",
+ "psr/http-message": "^1.1 || ^2.0",
+ "ralouphie/getallheaders": "^3.0"
+ },
+ "provide": {
+ "psr/http-factory-implementation": "1.0",
+ "psr/http-message-implementation": "1.0"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.8.2",
+ "http-interop/http-factory-tests": "^0.9",
+ "phpunit/phpunit": "^8.5.36 || ^9.6.15"
+ },
+ "suggest": {
+ "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
+ },
+ "type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": false
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Psr7\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "George Mponos",
+ "email": "gmponos@gmail.com",
+ "homepage": "https://github.com/gmponos"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://github.com/sagikazarmark"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://sagikazarmark.hu"
+ }
+ ],
+ "description": "PSR-7 message implementation that also provides common utility methods",
+ "keywords": [
+ "http",
+ "message",
+ "psr-7",
+ "request",
+ "response",
+ "stream",
+ "uri",
+ "url"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/psr7/issues",
+ "source": "https://github.com/guzzle/psr7/tree/2.6.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-12-03T20:05:35+00:00"
+ },
{
"name": "laminas/laminas-code",
"version": "4.13.0",
@@ -1606,6 +2044,194 @@
],
"time": "2024-04-12T21:02:21+00:00"
},
+ {
+ "name": "php-http/discovery",
+ "version": "1.19.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-http/discovery.git",
+ "reference": "0700efda8d7526335132360167315fdab3aeb599"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-http/discovery/zipball/0700efda8d7526335132360167315fdab3aeb599",
+ "reference": "0700efda8d7526335132360167315fdab3aeb599",
+ "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.19.4"
+ },
+ "time": "2024-03-29T13:00:05+00:00"
+ },
+ {
+ "name": "php-http/httplug",
+ "version": "2.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-http/httplug.git",
+ "reference": "625ad742c360c8ac580fcc647a1541d29e257f67"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-http/httplug/zipball/625ad742c360c8ac580fcc647a1541d29e257f67",
+ "reference": "625ad742c360c8ac580fcc647a1541d29e257f67",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0",
+ "php-http/promise": "^1.1",
+ "psr/http-client": "^1.0",
+ "psr/http-message": "^1.0 || ^2.0"
+ },
+ "require-dev": {
+ "friends-of-phpspec/phpspec-code-coverage": "^4.1 || ^5.0 || ^6.0",
+ "phpspec/phpspec": "^5.1 || ^6.0 || ^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Http\\Client\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Eric GELOEN",
+ "email": "geloen.eric@gmail.com"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://sagikazarmark.hu"
+ }
+ ],
+ "description": "HTTPlug, the HTTP client abstraction for PHP",
+ "homepage": "http://httplug.io",
+ "keywords": [
+ "client",
+ "http"
+ ],
+ "support": {
+ "issues": "https://github.com/php-http/httplug/issues",
+ "source": "https://github.com/php-http/httplug/tree/2.4.0"
+ },
+ "time": "2023-04-14T15:10:03+00:00"
+ },
+ {
+ "name": "php-http/promise",
+ "version": "1.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-http/promise.git",
+ "reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-http/promise/zipball/fc85b1fba37c169a69a07ef0d5a8075770cc1f83",
+ "reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "require-dev": {
+ "friends-of-phpspec/phpspec-code-coverage": "^4.3.2 || ^6.3",
+ "phpspec/phpspec": "^5.1.2 || ^6.2 || ^7.4"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Http\\Promise\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Joel Wurtz",
+ "email": "joel.wurtz@gmail.com"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com"
+ }
+ ],
+ "description": "Promise used for asynchronous HTTP requests",
+ "homepage": "http://httplug.io",
+ "keywords": [
+ "promise"
+ ],
+ "support": {
+ "issues": "https://github.com/php-http/promise/issues",
+ "source": "https://github.com/php-http/promise/tree/1.3.1"
+ },
+ "time": "2024-03-15T13:55:21+00:00"
+ },
{
"name": "phpdocumentor/reflection-common",
"version": "2.2.0",
@@ -1973,37 +2599,194 @@
"psr"
],
"support": {
- "issues": "https://github.com/php-fig/container/issues",
- "source": "https://github.com/php-fig/container/tree/2.0.2"
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
+ },
+ "time": "2021-11-05T16:47:00+00:00"
+ },
+ {
+ "name": "psr/event-dispatcher",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/event-dispatcher.git",
+ "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
+ "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\EventDispatcher\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Standard interfaces for event handling.",
+ "keywords": [
+ "events",
+ "psr",
+ "psr-14"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/event-dispatcher/issues",
+ "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
+ },
+ "time": "2019-01-08T18:20:26+00:00"
+ },
+ {
+ "name": "psr/http-client",
+ "version": "1.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-client.git",
+ "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
+ "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0 || ^8.0",
+ "psr/http-message": "^1.0 || ^2.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Client\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP clients",
+ "homepage": "https://github.com/php-fig/http-client",
+ "keywords": [
+ "http",
+ "http-client",
+ "psr",
+ "psr-18"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-client"
+ },
+ "time": "2023-09-23T14:17:50+00:00"
+ },
+ {
+ "name": "psr/http-factory",
+ "version": "1.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-factory.git",
+ "reference": "e616d01114759c4c489f93b099585439f795fe35"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
+ "reference": "e616d01114759c4c489f93b099585439f795fe35",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0.0",
+ "psr/http-message": "^1.0 || ^2.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interfaces for PSR-7 HTTP message factories",
+ "keywords": [
+ "factory",
+ "http",
+ "message",
+ "psr",
+ "psr-17",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-factory/tree/1.0.2"
},
- "time": "2021-11-05T16:47:00+00:00"
+ "time": "2023-04-10T20:10:41+00:00"
},
{
- "name": "psr/event-dispatcher",
- "version": "1.0.0",
+ "name": "psr/http-message",
+ "version": "2.0",
"source": {
"type": "git",
- "url": "https://github.com/php-fig/event-dispatcher.git",
- "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
+ "url": "https://github.com/php-fig/http-message.git",
+ "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
- "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
+ "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"shasum": ""
},
"require": {
- "php": ">=7.2.0"
+ "php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
- "Psr\\EventDispatcher\\": "src/"
+ "Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -2013,20 +2796,23 @@
"authors": [
{
"name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
+ "homepage": "https://www.php-fig.org/"
}
],
- "description": "Standard interfaces for event handling.",
+ "description": "Common interface for HTTP messages",
+ "homepage": "https://github.com/php-fig/http-message",
"keywords": [
- "events",
+ "http",
+ "http-message",
"psr",
- "psr-14"
+ "psr-7",
+ "request",
+ "response"
],
"support": {
- "issues": "https://github.com/php-fig/event-dispatcher/issues",
- "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
+ "source": "https://github.com/php-fig/http-message/tree/2.0"
},
- "time": "2019-01-08T18:20:26+00:00"
+ "time": "2023-04-04T09:54:51+00:00"
},
{
"name": "psr/link",
@@ -2134,6 +2920,50 @@
},
"time": "2021-07-14T16:46:02+00:00"
},
+ {
+ "name": "ralouphie/getallheaders",
+ "version": "3.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ralouphie/getallheaders.git",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpunit/phpunit": "^5 || ^6.5"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/getallheaders.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ralph Khattar",
+ "email": "ralph.khattar@gmail.com"
+ }
+ ],
+ "description": "A polyfill for getallheaders.",
+ "support": {
+ "issues": "https://github.com/ralouphie/getallheaders/issues",
+ "source": "https://github.com/ralouphie/getallheaders/tree/develop"
+ },
+ "time": "2019-03-08T08:55:37+00:00"
+ },
{
"name": "symfony/asset",
"version": "v7.0.3",
@@ -2870,6 +3700,78 @@
],
"time": "2024-03-19T09:29:21+00:00"
},
+ {
+ "name": "symfony/doctrine-messenger",
+ "version": "v7.0.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/doctrine-messenger.git",
+ "reference": "227cbb2cda296d724a8e08376ad6db73a0335538"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/227cbb2cda296d724a8e08376ad6db73a0335538",
+ "reference": "227cbb2cda296d724a8e08376ad6db73a0335538",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/dbal": "^3.6|^4",
+ "php": ">=8.2",
+ "symfony/messenger": "^6.4|^7.0",
+ "symfony/service-contracts": "^2.5|^3"
+ },
+ "conflict": {
+ "doctrine/persistence": "<1.3"
+ },
+ "require-dev": {
+ "doctrine/persistence": "^1.3|^2|^3",
+ "symfony/property-access": "^6.4|^7.0",
+ "symfony/serializer": "^6.4|^7.0"
+ },
+ "type": "symfony-messenger-bridge",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Messenger\\Bridge\\Doctrine\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Doctrine Messenger Bridge",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/doctrine-messenger/tree/v7.0.6"
+ },
+ "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-03-19T09:26:35+00:00"
+ },
{
"name": "symfony/dotenv",
"version": "v7.0.4",
@@ -4113,6 +5015,84 @@
],
"time": "2024-01-23T15:02:46+00:00"
},
+ {
+ "name": "symfony/lock",
+ "version": "v7.0.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/lock.git",
+ "reference": "c1fc92e5ba2a4d397751ac0df06689a187059402"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/lock/zipball/c1fc92e5ba2a4d397751ac0df06689a187059402",
+ "reference": "c1fc92e5ba2a4d397751ac0df06689a187059402",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "psr/log": "^1|^2|^3"
+ },
+ "conflict": {
+ "doctrine/dbal": "<3.6",
+ "symfony/cache": "<6.4"
+ },
+ "require-dev": {
+ "doctrine/dbal": "^3.6|^4",
+ "predis/predis": "^1.1|^2.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Lock\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jérémy Derussé",
+ "email": "jeremy@derusse.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Creates and manages locks, a mechanism to provide exclusive access to a shared resource",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "cas",
+ "flock",
+ "locking",
+ "mutex",
+ "redlock",
+ "semaphore"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/lock/tree/v7.0.6"
+ },
+ "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-03-19T09:26:35+00:00"
+ },
{
"name": "symfony/mailer",
"version": "v7.0.6",
@@ -4193,6 +5173,92 @@
],
"time": "2024-03-28T09:20:36+00:00"
},
+ {
+ "name": "symfony/messenger",
+ "version": "v7.0.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/messenger.git",
+ "reference": "4e281ef8bf5397be36fe14d64eb665fa12a945ad"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/messenger/zipball/4e281ef8bf5397be36fe14d64eb665fa12a945ad",
+ "reference": "4e281ef8bf5397be36fe14d64eb665fa12a945ad",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "psr/log": "^1|^2|^3",
+ "symfony/clock": "^6.4|^7.0"
+ },
+ "conflict": {
+ "symfony/console": "<6.4",
+ "symfony/event-dispatcher": "<6.4",
+ "symfony/event-dispatcher-contracts": "<2.5",
+ "symfony/framework-bundle": "<6.4",
+ "symfony/http-kernel": "<6.4",
+ "symfony/serializer": "<6.4"
+ },
+ "require-dev": {
+ "psr/cache": "^1.0|^2.0|^3.0",
+ "symfony/console": "^6.4|^7.0",
+ "symfony/dependency-injection": "^6.4|^7.0",
+ "symfony/event-dispatcher": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/process": "^6.4|^7.0",
+ "symfony/property-access": "^6.4|^7.0",
+ "symfony/rate-limiter": "^6.4|^7.0",
+ "symfony/routing": "^6.4|^7.0",
+ "symfony/serializer": "^6.4|^7.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/stopwatch": "^6.4|^7.0",
+ "symfony/validator": "^6.4|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Messenger\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Samuel Roze",
+ "email": "samuel.roze@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Helps applications send and receive messages to/from other applications or via message queues",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/messenger/tree/v7.0.6"
+ },
+ "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-03-19T11:57:22+00:00"
+ },
{
"name": "symfony/mime",
"version": "v7.0.6",
@@ -7112,34 +8178,34 @@
},
{
"name": "twig/extra-bundle",
- "version": "v3.8.0",
+ "version": "v3.9.3",
"source": {
"type": "git",
"url": "https://github.com/twigphp/twig-extra-bundle.git",
- "reference": "32807183753de0388c8e59f7ac2d13bb47311140"
+ "reference": "ef6869adf1fdab66f7e495771a7ba01496ffc0d5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/32807183753de0388c8e59f7ac2d13bb47311140",
- "reference": "32807183753de0388c8e59f7ac2d13bb47311140",
+ "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/ef6869adf1fdab66f7e495771a7ba01496ffc0d5",
+ "reference": "ef6869adf1fdab66f7e495771a7ba01496ffc0d5",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
- "symfony/framework-bundle": "^5.4|^6.0|^7.0",
- "symfony/twig-bundle": "^5.4|^6.0|^7.0",
+ "symfony/framework-bundle": "^5.4|^6.4|^7.0",
+ "symfony/twig-bundle": "^5.4|^6.4|^7.0",
"twig/twig": "^3.0"
},
"require-dev": {
"league/commonmark": "^1.0|^2.0",
"symfony/phpunit-bridge": "^6.4|^7.0",
"twig/cache-extra": "^3.0",
- "twig/cssinliner-extra": "^2.12|^3.0",
- "twig/html-extra": "^2.12|^3.0",
- "twig/inky-extra": "^2.12|^3.0",
- "twig/intl-extra": "^2.12|^3.0",
- "twig/markdown-extra": "^2.12|^3.0",
- "twig/string-extra": "^2.12|^3.0"
+ "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": {
@@ -7170,7 +8236,7 @@
"twig"
],
"support": {
- "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.8.0"
+ "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.9.3"
},
"funding": [
{
@@ -7182,34 +8248,41 @@
"type": "tidelift"
}
],
- "time": "2023-11-21T14:02:01+00:00"
+ "time": "2024-04-18T09:24:21+00:00"
},
{
"name": "twig/twig",
- "version": "v3.8.0",
+ "version": "v3.9.3",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
- "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d"
+ "reference": "a842d75fed59cdbcbd3a3ad7fb9eb768fc350d58"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d",
- "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d",
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/a842d75fed59cdbcbd3a3ad7fb9eb768fc350d58",
+ "reference": "a842d75fed59cdbcbd3a3ad7fb9eb768fc350d58",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3",
"symfony/polyfill-php80": "^1.22"
},
"require-dev": {
"psr/container": "^1.0|^2.0",
- "symfony/phpunit-bridge": "^5.4.9|^6.3|^7.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/"
}
@@ -7242,7 +8315,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
- "source": "https://github.com/twigphp/Twig/tree/v3.8.0"
+ "source": "https://github.com/twigphp/Twig/tree/v3.9.3"
},
"funding": [
{
@@ -7254,7 +8327,7 @@
"type": "tidelift"
}
],
- "time": "2023-11-21T18:54:41+00:00"
+ "time": "2024-04-18T11:59:33+00:00"
},
{
"name": "webmozart/assert",
diff --git a/config/doctrine/orm/Dinosaur.orm.xml b/config/doctrine/orm/Dinosaur.orm.xml
index 2dd902f..e1f769d 100644
--- a/config/doctrine/orm/Dinosaur.orm.xml
+++ b/config/doctrine/orm/Dinosaur.orm.xml
@@ -24,6 +24,11 @@
target-entity="App\Entity\Species"
inversed-by="dinosaurs" />
+
+
diff --git a/config/doctrine/orm/Park.orm.xml b/config/doctrine/orm/Park.orm.xml
new file mode 100644
index 0000000..390f843
--- /dev/null
+++ b/config/doctrine/orm/Park.orm.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/packages/http_discovery.yaml b/config/packages/http_discovery.yaml
new file mode 100644
index 0000000..2a789e7
--- /dev/null
+++ b/config/packages/http_discovery.yaml
@@ -0,0 +1,10 @@
+services:
+ Psr\Http\Message\RequestFactoryInterface: '@http_discovery.psr17_factory'
+ Psr\Http\Message\ResponseFactoryInterface: '@http_discovery.psr17_factory'
+ Psr\Http\Message\ServerRequestFactoryInterface: '@http_discovery.psr17_factory'
+ Psr\Http\Message\StreamFactoryInterface: '@http_discovery.psr17_factory'
+ Psr\Http\Message\UploadedFileFactoryInterface: '@http_discovery.psr17_factory'
+ Psr\Http\Message\UriFactoryInterface: '@http_discovery.psr17_factory'
+
+ http_discovery.psr17_factory:
+ class: Http\Discovery\Psr17Factory
diff --git a/config/packages/lock.yaml b/config/packages/lock.yaml
new file mode 100644
index 0000000..574879f
--- /dev/null
+++ b/config/packages/lock.yaml
@@ -0,0 +1,2 @@
+framework:
+ lock: '%env(LOCK_DSN)%'
diff --git a/config/packages/messenger.yaml b/config/packages/messenger.yaml
new file mode 100644
index 0000000..697a115
--- /dev/null
+++ b/config/packages/messenger.yaml
@@ -0,0 +1,31 @@
+framework:
+ messenger:
+ default_bus: command_bus
+ buses:
+ command_bus:
+ middleware:
+ - doctrine_transaction
+ - dispatch_after_current_bus
+ - App\Middleware\LockMiddleware
+ event_bus:
+ default_middleware: allow_no_handlers
+ middleware:
+ - doctrine_transaction
+ failure_transport: failed
+ transports:
+ async_high_priority:
+ dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
+ options:
+ queue_name: high_priority
+ async_low_priority:
+ dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
+ options:
+ queue_name: low_priority
+ failed:
+ dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
+ options:
+ queue_name: failed
+ routing:
+ 'App\Message\Food\Consume': async_low_priority
+ 'App\Message\Food\Refill': async_high_priority
+ 'App\Event\AsyncLowPriorityEvent': async_low_priority
diff --git a/config/services.yaml b/config/services.yaml
index 1d3246d..9a20d90 100644
--- a/config/services.yaml
+++ b/config/services.yaml
@@ -24,5 +24,16 @@ services:
- '../src/Entity/'
- '../src/Kernel.php'
+ App\Bus\CommandBus:
+ $messageBus: '@command_bus'
+
+ Elastic\Elasticsearch\Client:
+ class: Elastic\Elasticsearch\Client
+ factory: ['Elastic\Elasticsearch\ClientBuilder', 'fromConfig']
+ arguments:
+ -
+ hosts:
+ - 'elasticsearch:9200'
+
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
diff --git a/docker-compose.yml b/docker-compose.yml
index 6f9f8ba..1b86bb5 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -42,5 +42,16 @@ services:
- db-data:/var/lib/mysql:rw
restart: unless-stopped
+ elasticsearch:
+ image: docker.elastic.co/elasticsearch/elasticsearch:7.16.3
+ volumes:
+ - 'elasticsearch:/usr/share/elasticsearch/data'
+ ports:
+ - 9200:9200
+ environment:
+ - discovery.type=single-node
+ - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
+
volumes:
db-data: ~
+ elasticsearch: ~
diff --git a/migrations/Version20230208124132.php b/migrations/Version20230208124132.php
new file mode 100644
index 0000000..7e3d23f
--- /dev/null
+++ b/migrations/Version20230208124132.php
@@ -0,0 +1,29 @@
+addSql('CREATE TABLE park (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, food_amount INT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('CREATE TABLE messenger_messages (id BIGINT AUTO_INCREMENT NOT NULL, body LONGTEXT NOT NULL, headers LONGTEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at DATETIME NOT NULL, available_at DATETIME NOT NULL, delivered_at DATETIME DEFAULT NULL, INDEX IDX_75EA56E0FB7336F0 (queue_name), INDEX IDX_75EA56E0E3BD61CE (available_at), INDEX IDX_75EA56E016BA31DB (delivered_at), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('ALTER TABLE dinosaur ADD park_id INT DEFAULT NULL');
+ $this->addSql('ALTER TABLE dinosaur ADD CONSTRAINT FK_DAEDC56E44990C25 FOREIGN KEY (park_id) REFERENCES park (id)');
+ $this->addSql('CREATE INDEX IDX_DAEDC56E44990C25 ON dinosaur (park_id)');
+ }
+
+ public function down(Schema $schema): void
+ {
+ $this->addSql('ALTER TABLE dinosaur DROP FOREIGN KEY FK_DAEDC56E44990C25');
+ $this->addSql('DROP TABLE park');
+ $this->addSql('DROP TABLE messenger_messages');
+ $this->addSql('DROP INDEX IDX_DAEDC56E44990C25 ON dinosaur');
+ $this->addSql('ALTER TABLE dinosaur DROP park_id');
+ }
+}
diff --git a/src/Bus/CommandBus.php b/src/Bus/CommandBus.php
new file mode 100644
index 0000000..e002dc5
--- /dev/null
+++ b/src/Bus/CommandBus.php
@@ -0,0 +1,23 @@
+handle($input);
+ }
+}
diff --git a/src/Command/ConsumeCommand.php b/src/Command/ConsumeCommand.php
new file mode 100644
index 0000000..20f9ca8
--- /dev/null
+++ b/src/Command/ConsumeCommand.php
@@ -0,0 +1,49 @@
+setDescription('Dispatch some food comsumption messages.')
+ ->setHelp('This command allows you dispatch some food consumptions messages...')
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $dinosaurs = $this->dinosaurRepository->findAll();
+
+ for ($i = 0; $i < 100; $i++) {
+ $randomDinoKey = array_rand($dinosaurs);
+
+ $dinosaur = $dinosaurs[$randomDinoKey];
+
+ $consumeMessage = new Consume($dinosaur->getId(), $dinosaur->getName());
+
+ $this->bus->dispatch($consumeMessage);
+ }
+
+ return Command::SUCCESS;
+ }
+}
diff --git a/src/Command/RefillCommand.php b/src/Command/RefillCommand.php
new file mode 100644
index 0000000..fe27627
--- /dev/null
+++ b/src/Command/RefillCommand.php
@@ -0,0 +1,37 @@
+setDescription('Dispatch a food refill message.')
+ ->setHelp('This command allows you to dispatch a food refill command...')
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $this->bus->dispatch(new Refill());
+
+ return Command::SUCCESS;
+ }
+}
diff --git a/src/Controller/DinosaursController.php b/src/Controller/DinosaursController.php
index 4ced07c..14d7e43 100644
--- a/src/Controller/DinosaursController.php
+++ b/src/Controller/DinosaursController.php
@@ -2,9 +2,13 @@
namespace App\Controller;
+use App\Bus\CommandBus;
use App\Entity\Dinosaur;
use App\Form\Type\DinosaurType;
use App\Form\Type\SearchType;
+use App\Message\Dinosaur\Create;
+use App\Message\Dinosaur\Delete;
+use App\Message\Dinosaur\Edit;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
@@ -13,6 +17,11 @@
final class DinosaursController extends AbstractController
{
+ public function __construct(
+ private CommandBus $bus
+ ) {
+ }
+
#[Route('/dinosaurs', name: 'app_list_dinosaurs')]
public function list(Request $request, ManagerRegistry $doctrine): Response
{
@@ -58,20 +67,28 @@ public function single(string $id, ManagerRegistry $doctrine): Response
}
#[Route('/dinosaurs/create', name: 'app_create_dinosaur')]
- public function create(Request $request, ManagerRegistry $doctrine): Response
+ public function create(Request $request): Response
{
$form = $this->createForm(DinosaurType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
- $em = $doctrine->getManager();
- $dinosaur = $form->getData();
-
- $em->persist($dinosaur);
- $em->flush();
-
- $this->addFlash('success', 'The dinosaur has been created!');
+ $data = $form->getData();
+
+ $result = $this->bus->dispatch(new Create(
+ name: $data->getName(),
+ gender: $data->getGender(),
+ eyesColor: $data->getEyesColor(),
+ age: $data->getAge(),
+ speciesId: $data->getSpecies()->getId(),
+ parkId: $data->getPark()->getId()
+ ));
+
+ $this->addFlash('success', sprintf(
+ 'The dinosaur with id %s has been created!',
+ $result->id
+ ));
return $this->redirectToRoute('app_list_dinosaurs');
}
@@ -86,7 +103,7 @@ public function create(Request $request, ManagerRegistry $doctrine): Response
name: 'app_edit_dinosaur',
requirements: ['id' => '\d+']
)]
- public function edit(Request $request, int $id, ManagerRegistry $doctrine): Response
+ public function edit(Request $request, string $id, ManagerRegistry $doctrine): Response
{
$dinosaur = $doctrine
->getRepository(Dinosaur::class)
@@ -101,10 +118,16 @@ public function edit(Request $request, int $id, ManagerRegistry $doctrine): Resp
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
- $em = $doctrine->getManager();
- $dinosaur = $form->getData();
+ $data = $form->getData();
- $em->flush();
+ $this->bus->dispatch(new Edit(
+ id: $id,
+ name: $data->getName(),
+ gender: $data->getGender(),
+ eyesColor: $data->getEyesColor(),
+ age: $data->getAge(),
+ speciesId: $data->getSpecies()->getId()
+ ));
$this->addFlash('success', 'The dinosaur has been edited!');
@@ -121,19 +144,9 @@ public function edit(Request $request, int $id, ManagerRegistry $doctrine): Resp
name: 'app_remove_dinosaur',
requirements: ['id' => '\d+']
)]
- public function remove(int $id, ManagerRegistry $doctrine): Response
+ public function remove(string $id): Response
{
- $dinosaur = $doctrine
- ->getRepository(Dinosaur::class)
- ->find($id);
-
- if (false === $dinosaur) {
- throw $this->createNotFoundException('The dinosaur you are looking for does not exists.');
- }
-
- $em = $doctrine->getManager();
- $em->remove($dinosaur);
- $em->flush();
+ $this->bus->dispatch(new Delete($id));
$this->addFlash('success', 'The dinosaur has been removed!');
diff --git a/src/Controller/SpeciesController.php b/src/Controller/SpeciesController.php
index 7d356f8..54d0cc9 100644
--- a/src/Controller/SpeciesController.php
+++ b/src/Controller/SpeciesController.php
@@ -2,8 +2,12 @@
namespace App\Controller;
+use App\Bus\CommandBus;
use App\Entity\Species;
use App\Form\Type\SpeciesType;
+use App\Message\Species\Delete;
+use App\Message\Species\Edit;
+use App\Message\Species\Create;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
@@ -12,6 +16,11 @@
final class SpeciesController extends AbstractController
{
+ public function __construct(
+ private CommandBus $bus
+ ) {
+ }
+
#[Route('/species', name: 'app_list_species')]
public function list(ManagerRegistry $doctrine): Response
{
@@ -32,13 +41,18 @@ public function create(Request $request, ManagerRegistry $doctrine): Response
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
- $em = $doctrine->getManager();
- $species = $form->getData();
+ $data = $form->getData();
- $em->persist($species);
- $em->flush();
+ $result = $this->bus->dispatch(new Create(
+ name: $data->getName(),
+ feeding: $data->getFeeding(),
+ habitats: $data->getHabitats()
+ ));
- $this->addFlash('success', 'The species has been created!');
+ $this->addFlash('success', sprintf(
+ 'The species with id %s has been created!',
+ $result->id
+ ));
return $this->redirectToRoute('app_list_species');
}
@@ -53,7 +67,7 @@ public function create(Request $request, ManagerRegistry $doctrine): Response
name: 'app_edit_species',
requirements: ['id' => '\d+']
)]
- public function edit(Request $request, int $id, ManagerRegistry $doctrine): Response
+ public function edit(Request $request, string $id, ManagerRegistry $doctrine): Response
{
$species = $doctrine
->getRepository(Species::class)
@@ -68,10 +82,14 @@ public function edit(Request $request, int $id, ManagerRegistry $doctrine): Resp
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
- $em = $doctrine->getManager();
- $species = $form->getData();
+ $data = $form->getData();
- $em->flush();
+ $this->bus->dispatch(new Edit(
+ id: $id,
+ name: $data->getName(),
+ feeding: $data->getFeeding(),
+ habitats: $data->getHabitats()
+ ));
$this->addFlash('success', 'The species has been edited!');
@@ -88,19 +106,9 @@ public function edit(Request $request, int $id, ManagerRegistry $doctrine): Resp
name: 'app_remove_species',
requirements: ['id' => '\d+']
)]
- public function remove(int $id, ManagerRegistry $doctrine): Response
+ public function remove(string $id): Response
{
- $species = $doctrine
- ->getRepository(Species::class)
- ->find($id);
-
- if (false === $species) {
- throw $this->createNotFoundException('The species you are looking for does not exists.');
- }
-
- $em = $doctrine->getManager();
- $em->remove($species);
- $em->flush();
+ $this->bus->dispatch(new Delete($id));
$this->addFlash('success', 'The species has been removed!');
diff --git a/src/DataFixtures/AppFixtures.php b/src/DataFixtures/AppFixtures.php
index fc71111..adb9527 100644
--- a/src/DataFixtures/AppFixtures.php
+++ b/src/DataFixtures/AppFixtures.php
@@ -2,6 +2,7 @@
namespace App\DataFixtures;
+use App\Entity\Park;
use App\Entity\Dinosaur;
use App\Entity\Species;
use App\Entity\User;
@@ -115,6 +116,10 @@ public function load(ObjectManager $manager): void
$manager->flush();
+ $park = new Park('Jurassic Park', 100);
+ $manager->persist($park);
+ $manager->flush();
+
/**
* Create dinosaurs.
*/
@@ -133,7 +138,8 @@ public function load(ObjectManager $manager): void
$gender[array_rand($gender)],
$speciesList[array_rand($speciesList)],
rand(1, 40),
- '#000000'
+ '#000000',
+ $park
);
$manager->persist($dinosaur);
diff --git a/src/Entity/Dinosaur.php b/src/Entity/Dinosaur.php
index b11a447..8e324a9 100644
--- a/src/Entity/Dinosaur.php
+++ b/src/Entity/Dinosaur.php
@@ -11,7 +11,8 @@ public function __construct(
private string $gender,
private Species $species,
private int $age,
- private string $eyesColor
+ private string $eyesColor,
+ private Park $park,
) {
}
@@ -69,4 +70,14 @@ public function setEyesColor(string $eyesColor): void
{
$this->eyesColor = $eyesColor;
}
+
+ public function getPark(): Park
+ {
+ return $this->park;
+ }
+
+ public function setPark(Park $park): void
+ {
+ $this->park = $park;
+ }
}
diff --git a/src/Entity/Park.php b/src/Entity/Park.php
new file mode 100644
index 0000000..d81061c
--- /dev/null
+++ b/src/Entity/Park.php
@@ -0,0 +1,59 @@
+name = $name;
+ $this->foodAmount = $foodAmount;
+ $this->dinosaurs = new ArrayCollection();
+ }
+
+ public function addDinosaurs(Dinosaur ...$dinosaur): void
+ {
+ $this->dinosaurs[] = $dinosaur;
+ }
+
+ public function getId(): int
+ {
+ return $this->id;
+ }
+
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ public function getFoodAmount(): int
+ {
+ return $this->foodAmount;
+ }
+
+ public function setFoodAmount(int $foodAmount): void
+ {
+ $this->foodAmount = $foodAmount;
+ }
+
+ public function getDinosaurs()
+ {
+ return $this->dinosaurs;
+ }
+}
diff --git a/src/Entity/Species.php b/src/Entity/Species.php
index 61d5a90..b5e1f54 100644
--- a/src/Entity/Species.php
+++ b/src/Entity/Species.php
@@ -15,9 +15,6 @@ public function __construct(
private array $habitats,
private string $feeding,
) {
- $this->name = $name;
- $this->habitats = $habitats;
- $this->feeding = $feeding;
$this->dinosaurs = new ArrayCollection();
}
diff --git a/src/Event/AbstractEvent.php b/src/Event/AbstractEvent.php
new file mode 100644
index 0000000..f04d592
--- /dev/null
+++ b/src/Event/AbstractEvent.php
@@ -0,0 +1,18 @@
+id;
+ }
+}
diff --git a/src/Event/AsyncLowPriorityEvent.php b/src/Event/AsyncLowPriorityEvent.php
new file mode 100644
index 0000000..e9ba284
--- /dev/null
+++ b/src/Event/AsyncLowPriorityEvent.php
@@ -0,0 +1,9 @@
+indexer->delete($event->getId());
+ }
+}
diff --git a/src/EventHandler/Dinosaur/UpsertDinosaurSummary.php b/src/EventHandler/Dinosaur/UpsertDinosaurSummary.php
new file mode 100644
index 0000000..752bf37
--- /dev/null
+++ b/src/EventHandler/Dinosaur/UpsertDinosaurSummary.php
@@ -0,0 +1,90 @@
+updateSummaryByDinosaur($event->getId());
+ }
+
+ #[AsMessageHandler]
+ public function handleDinosaurHasBeenUpdated(DinosaurHasBeenUpdated $event): void
+ {
+ $this->updateSummaryByDinosaur($event->getId());
+ }
+
+ #[AsMessageHandler]
+ public function handleFoodHasBeenConsumed(HasBeenConsumed $event): void
+ {
+ $this->updateSummariesByPark($event->getId());
+ }
+
+ #[AsMessageHandler]
+ public function handleFoodHasBeenRefilled(HasBeenRefilled $event): void
+ {
+ $this->updateSummariesByPark($event->getId());
+ }
+
+ #[AsMessageHandler]
+ public function handleSpeciesHasBeenUpdated(SpeciesHasBeenUpdated $event): void
+ {
+ $speciesId = $event->getId();
+
+ $species = $this->speciesRepository->find($speciesId);
+
+ if (null === $species) {
+ throw new \RuntimeException(sprintf(
+ 'Species with id "%s" not found',
+ $speciesId
+ ));
+ }
+
+ $dinosaurs = $this->dinosaurRepository->findBySpecies($species);
+
+ foreach ($dinosaurs as $dinosaur) {
+ $this->indexer->indexFromDinosaur($dinosaur);
+ }
+ }
+
+ private function updateSummaryByDinosaur(int $dinosaurId): void
+ {
+ $dinosaur = $this->dinosaurRepository->find($dinosaurId);
+
+ if (null === $dinosaur) {
+ throw new \RuntimeException(sprintf('Dinosaur with id "%s" not found', $dinosaurId));
+ }
+
+ $this->indexer->indexFromDinosaur($dinosaur);
+ }
+
+ private function updateSummariesByPark(int $parkId): void
+ {
+ $dinosaurs = $this->dinosaurRepository->findByPark($parkId);
+
+ foreach ($dinosaurs as $dinosaur) {
+ $this->indexer->indexFromDinosaur($dinosaur);
+ }
+ }
+}
diff --git a/src/EventListener/WorkerListener.php b/src/EventListener/WorkerListener.php
new file mode 100644
index 0000000..088f6a9
--- /dev/null
+++ b/src/EventListener/WorkerListener.php
@@ -0,0 +1,88 @@
+getWorker()->getMetadata()->getTransportNames();
+
+ $this->logger->log(LogLevel::NOTICE, sprintf(
+ 'Worker started. Transports priority : [%s]',
+ implode(', ', $transports)
+ ));
+ }
+
+ public function onWorkerStoppedEvent(WorkerStoppedEvent $event)
+ {
+ $this->logger->log(LogLevel::NOTICE, 'Worker stopped');
+ }
+
+ public function onWorkerMessageReceivedEvent(WorkerMessageReceivedEvent $event)
+ {
+ $envelope = $event->getEnvelope();
+
+ $message = $envelope->getMessage();
+ $messageClass = get_class($message);
+
+ $this->logger->log(LogLevel::NOTICE, sprintf('Received message %s', $messageClass));
+ }
+
+ public function onWorkerMessageHandledEvent(WorkerMessageHandledEvent $event)
+ {
+ $envelope = $event->getEnvelope();
+
+ $handledStamp = $envelope->last(HandledStamp::class);
+
+ if (null === $handledStamp) {
+ return;
+ }
+
+ $handlerName = $handledStamp->getHandlerName();
+
+ $message = $envelope->getMessage();
+ $messageClass = get_class($message);
+
+ $this->logger->log(LogLevel::NOTICE, sprintf('Message %s handled by %s', $messageClass, $handlerName));
+ }
+
+ public function onWorkerMessageFailedEvent(WorkerMessageFailedEvent $event)
+ {
+ $envelope = $event->getEnvelope();
+
+ $message = $envelope->getMessage();
+ $messageClass = get_class($message);
+
+ $this->logger->log(LogLevel::CRITICAL, sprintf('Message %s failed', $messageClass));
+ }
+
+ public function onWorkerRunningEvent()
+ {
+ $this->logger->log(LogLevel::NOTICE, 'Worker is running. Waiting for messages...');
+ }
+}
diff --git a/src/Form/Type/DinosaurType.php b/src/Form/Type/DinosaurType.php
index 9640754..73c0851 100644
--- a/src/Form/Type/DinosaurType.php
+++ b/src/Form/Type/DinosaurType.php
@@ -3,6 +3,7 @@
namespace App\Form\Type;
use App\Entity\Dinosaur;
+use App\Entity\Park;
use App\Entity\Species;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
@@ -30,6 +31,10 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
'class' => Species::class,
'choice_label' => 'name',
])
+ ->add('park', EntityType::class, [
+ 'class' => Park::class,
+ 'choice_label' => 'name'
+ ])
->add('age', NumberType::class)
->add('eyesColor', ColorType::class)
->add('submit', SubmitType::class);
@@ -46,6 +51,7 @@ public function configureOptions(OptionsResolver $resolver): void
$form->get('species')->getData(),
$form->get('age')->getData(),
$form->get('eyesColor')->getData(),
+ $form->get('park')->getData()
);
},
]);
diff --git a/src/Indexer.php b/src/Indexer.php
new file mode 100644
index 0000000..80be302
--- /dev/null
+++ b/src/Indexer.php
@@ -0,0 +1,48 @@
+getSpecies();
+ $park = $dinosaur->getPark();
+
+ $this->client->index([
+ 'index' => self::INDEX_NAME,
+ 'type' => '_doc',
+ 'id' => $dinosaur->getId(),
+ 'body' => [
+ 'name' => $dinosaur->getName(),
+ 'age' => $dinosaur->getAge(),
+ 'park_food_amount' => $park->getFoodAmount(),
+ 'park_name' => $park->getName(),
+ 'species_name' => $species->getName(),
+ 'habitats' => $species->getHabitats(),
+ 'feeding'=> $species->getFeeding(),
+ ],
+ ]);
+ }
+
+ public function delete(int $id)
+ {
+ $this->client->delete([
+ 'index' => self::INDEX_NAME,
+ 'type' => '_doc',
+ 'id' => $id,
+ ]);
+ }
+}
diff --git a/src/Message/Dinosaur/Create.php b/src/Message/Dinosaur/Create.php
new file mode 100644
index 0000000..5ccc485
--- /dev/null
+++ b/src/Message/Dinosaur/Create.php
@@ -0,0 +1,16 @@
+speciesRepository->find($message->speciesId)) {
+ throw new NotFoundHttpException("Species with id {$message->speciesId} not found");
+ }
+
+ if (!$park = $this->parkRepository->find($message->parkId)) {
+ throw new NotFoundHttpException("Park with id {$message->parkId} not found");
+ }
+
+ $dino = new Dinosaur(
+ name: $message->name,
+ gender: $message->gender,
+ species: $species,
+ age: $message->age,
+ eyesColor: $message->eyesColor,
+ park: $park
+ );
+
+ $this->dinosaurRepository->add($dino, flush: true);
+
+ $envelop = new Envelope(new HasBeenCreated($dino->getId()));
+
+ $this
+ ->eventBus
+ ->dispatch($envelop->with(new DispatchAfterCurrentBusStamp()))
+ ;
+
+ return new CreateMessageResult($dino->getId());
+ }
+}
diff --git a/src/MessageHandler/Dinosaur/Delete.php b/src/MessageHandler/Dinosaur/Delete.php
new file mode 100644
index 0000000..6e7495c
--- /dev/null
+++ b/src/MessageHandler/Dinosaur/Delete.php
@@ -0,0 +1,43 @@
+dinosaurRepository->find($message->id)) {
+ throw new NotFoundHttpException("Dinosaur with id {$message->id} not found");
+ }
+
+ $this->entityManager->remove($dinosaur);
+
+ $envelop = new Envelope(
+ new HasBeenDeleted($message->id)
+ );
+
+ $this->eventBus->dispatch(
+ $envelop->with(new DispatchAfterCurrentBusStamp())
+ );
+ }
+}
diff --git a/src/MessageHandler/Dinosaur/Edit.php b/src/MessageHandler/Dinosaur/Edit.php
new file mode 100644
index 0000000..64ab1de
--- /dev/null
+++ b/src/MessageHandler/Dinosaur/Edit.php
@@ -0,0 +1,47 @@
+dinosaurRepository->find($message->id)) {
+ throw new NotFoundHttpException("Dinosaur with id {$message->id} not found");
+ }
+
+ if (!$species = $this->speciesRepository->find($message->speciesId)) {
+ throw new NotFoundHttpException("Species with id {$message->id} not found");
+ }
+
+ $dinosaur->setName($message->name);
+ $dinosaur->setEyesColor($message->eyesColor);
+ $dinosaur->setAge($message->age);
+ $dinosaur->setSpecies($species);
+
+ $envelop = new Envelope(new HasBeenUpdated($dinosaur->getId()));
+
+ $this
+ ->eventBus
+ ->dispatch($envelop->with(new DispatchAfterCurrentBusStamp()))
+ ;
+ }
+}
diff --git a/src/MessageHandler/Food/Consume.php b/src/MessageHandler/Food/Consume.php
new file mode 100644
index 0000000..560389b
--- /dev/null
+++ b/src/MessageHandler/Food/Consume.php
@@ -0,0 +1,65 @@
+dinosaurId;
+
+ $dinosaursRepository = $this->em->getRepository(Dinosaur::class);
+
+ /** @var Dinosaur $dinosaur */
+ $dinosaur = $dinosaursRepository->find($dinosaurId);
+
+ $park = $dinosaur->getPark();
+
+ $consumedAmout = random_int(1, 10);
+
+ if ($consumedAmout > $park->getFoodAmount()) {
+ throw new DomainException(sprintf(
+ 'Not enough food to feed %s',
+ $dinosaur->getName()
+ ));
+ }
+
+ $this->logger->info(sprintf(
+ '%s is consuming %d stacks of food. He needs to rest...',
+ $dinosaur->getName(),
+ $consumedAmout
+ ));
+
+ sleep($consumedAmout);
+
+ $park->setFoodAmount($park->getFoodAmount() - $consumedAmout);
+
+ $envelop = new Envelope(new HasBeenConsumed($park->getId()));
+
+ $this
+ ->eventBus
+ ->dispatch($envelop->with(new DispatchAfterCurrentBusStamp()))
+ ;
+ }
+}
diff --git a/src/MessageHandler/Food/Refill.php b/src/MessageHandler/Food/Refill.php
new file mode 100644
index 0000000..e84d4fd
--- /dev/null
+++ b/src/MessageHandler/Food/Refill.php
@@ -0,0 +1,54 @@
+logger->info('Refilling food');
+
+ $parkRepository = $this->entityManager->getRepository(Park::class);
+
+ /** @var Park[] $parks */
+ $parks = $parkRepository->findAll();
+
+ $dinosaurIsAttacking = random_int(0, 10);
+
+ if ($dinosaurIsAttacking < 5) {
+ throw new DomainException('Dinosaur is attacking cannot refill food');
+ }
+
+ foreach ($parks as $park) {
+ $park->setFoodAmount(100);
+ }
+
+ $envelop = new Envelope(new HasBeenRefilled($park->getId()));
+
+ $this
+ ->eventBus
+ ->dispatch($envelop->with(new DispatchAfterCurrentBusStamp()))
+ ;
+ }
+}
diff --git a/src/MessageHandler/Species/Create.php b/src/MessageHandler/Species/Create.php
new file mode 100644
index 0000000..02c1185
--- /dev/null
+++ b/src/MessageHandler/Species/Create.php
@@ -0,0 +1,44 @@
+name,
+ habitats: $message->habitats,
+ feeding: $message->feeding
+ );
+
+ $this->speciesRepository->add($species, flush: true);
+
+ $envelop = new Envelope(new HasBeenCreated(
+ $species->getId()
+ ));
+
+ $this
+ ->eventBus
+ ->dispatch($envelop->with(new DispatchAfterCurrentBusStamp()));
+
+ return new CreateMessageResult($species->getId());
+ }
+}
diff --git a/src/MessageHandler/Species/Delete.php b/src/MessageHandler/Species/Delete.php
new file mode 100644
index 0000000..54b24ba
--- /dev/null
+++ b/src/MessageHandler/Species/Delete.php
@@ -0,0 +1,29 @@
+speciesRepository->find($message->id)) {
+ throw new NotFoundHttpException("Species with id {$message->id} not found");
+ }
+
+ $this->entityManager->remove($species);
+ }
+}
diff --git a/src/MessageHandler/Species/Edit.php b/src/MessageHandler/Species/Edit.php
new file mode 100644
index 0000000..a138739
--- /dev/null
+++ b/src/MessageHandler/Species/Edit.php
@@ -0,0 +1,42 @@
+speciesRepository->find($message->id)) {
+ throw new NotFoundHttpException("Species with id {$message->id} not found");
+ }
+
+ $species->setName($message->name);
+ $species->setFeeding($message->feeding);
+ $species->setHabitats($message->habitats);
+
+ $envelop = new Envelope(new HasBeenUpdated($message->id));
+
+ $this
+ ->eventBus
+ ->dispatch($envelop->with(new DispatchAfterCurrentBusStamp()))
+ ;
+ }
+}
diff --git a/src/MessageResults/Dinosaur/Create.php b/src/MessageResults/Dinosaur/Create.php
new file mode 100644
index 0000000..9a317e2
--- /dev/null
+++ b/src/MessageResults/Dinosaur/Create.php
@@ -0,0 +1,13 @@
+getMessage();
+
+ if (!$message instanceof Lockable) {
+ return $stack->next()->handle($envelope, $stack);
+ }
+
+ if ([] === $envelope->all(LockStamp::class)) {
+ $envelope = $envelope->with(new LockStamp(
+ $message->dinosaurId
+ ));
+
+ return $stack->next()->handle($envelope, $stack);
+ }
+
+ /** @var LockStamp $lockStamp */
+ $lockStamp = $envelope->last(LockStamp::class);
+
+ $lock = $this->lockFactory->createLock((string) $lockStamp->lockKey);
+
+ if ($lock->acquire()) {
+ $return = $stack->next()->handle($envelope, $stack);
+
+ $lock->release();
+
+ return $return;
+ }
+
+ throw new RuntimeException("Unable to acquire the lock for {$message->dinosaurName}");
+ }
+}
diff --git a/src/Repository/DinosaurRepository.php b/src/Repository/DinosaurRepository.php
index 1016b70..d902df2 100644
--- a/src/Repository/DinosaurRepository.php
+++ b/src/Repository/DinosaurRepository.php
@@ -13,6 +13,14 @@ public function __construct(ManagerRegistry $registry)
parent::__construct($registry, Dinosaur::class);
}
+ public function add(Dinosaur $dinosaur, bool $flush = false): void
+ {
+ $this->getEntityManager()->persist($dinosaur);
+ if ($flush) {
+ $this->getEntityManager()->flush();
+ }
+ }
+
public function search(?string $q): array
{
if (null === $q) {
diff --git a/src/Repository/ParkRepository.php b/src/Repository/ParkRepository.php
new file mode 100644
index 0000000..ffd960b
--- /dev/null
+++ b/src/Repository/ParkRepository.php
@@ -0,0 +1,15 @@
+getEntityManager()->persist($species);
+ if ($flush) {
+ $this->getEntityManager()->flush();
+ }
+ }
}
diff --git a/src/Stamp/LockStamp.php b/src/Stamp/LockStamp.php
new file mode 100644
index 0000000..587381d
--- /dev/null
+++ b/src/Stamp/LockStamp.php
@@ -0,0 +1,13 @@
+