feat(mail) : install symfony/messenger + browser-kit + ENCRYPTION_KEY test (deps Phase 3)

- ajoute symfony/messenger ^8.0 et symfony/doctrine-messenger ^8.0 pour la sync mail async
- ajoute symfony/browser-kit + css-selector en dev pour tests fonctionnels WebTestCase
- ENCRYPTION_KEY ajoutee dans phpunit.dist.xml pour permettre le chiffrement en test
- MESSENGER_TRANSPORT_DSN configure (Doctrine), messenger.yaml minimal (sera enrichi en Task 12)
- fix(orm) : ClientTicket - migre uniqueConstraints en attribut separe (Doctrine ORM 4 deprecation)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 00:05:49 +02:00
parent cbbc491d69
commit 696b40ca80
7 changed files with 408 additions and 12 deletions

7
.env
View File

@@ -26,3 +26,10 @@ ENCRYPTION_KEY=change_me_in_env_local
# postgresql+advisory://db_user:db_password@localhost/db_name # postgresql+advisory://db_user:db_password@localhost/db_name
LOCK_DSN=flock LOCK_DSN=flock
###< symfony/lock ### ###< symfony/lock ###
###> symfony/messenger ###
# Choose one of the transports below
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
###< symfony/messenger ###

View File

@@ -21,6 +21,7 @@
"sabre/vobject": "^4.5", "sabre/vobject": "^4.5",
"symfony/asset": "8.0.*", "symfony/asset": "8.0.*",
"symfony/console": "8.0.*", "symfony/console": "8.0.*",
"symfony/doctrine-messenger": "^8.0",
"symfony/dotenv": "8.0.*", "symfony/dotenv": "8.0.*",
"symfony/expression-language": "8.0.*", "symfony/expression-language": "8.0.*",
"symfony/flex": "^2", "symfony/flex": "^2",
@@ -28,6 +29,7 @@
"symfony/http-client": "8.0.*", "symfony/http-client": "8.0.*",
"symfony/lock": "8.0.*", "symfony/lock": "8.0.*",
"symfony/mcp-bundle": "^0.6.0", "symfony/mcp-bundle": "^0.6.0",
"symfony/messenger": "^8.0",
"symfony/mime": "8.0.*", "symfony/mime": "8.0.*",
"symfony/monolog-bundle": "^4.0", "symfony/monolog-bundle": "^4.0",
"symfony/property-access": "8.0.*", "symfony/property-access": "8.0.*",
@@ -95,6 +97,8 @@
"require-dev": { "require-dev": {
"doctrine/doctrine-fixtures-bundle": "^4.3", "doctrine/doctrine-fixtures-bundle": "^4.3",
"friendsofphp/php-cs-fixer": "^3.94", "friendsofphp/php-cs-fixer": "^3.94",
"phpunit/phpunit": "^13.0" "phpunit/phpunit": "^13.0",
"symfony/browser-kit": "^8.0",
"symfony/css-selector": "^8.0"
} }
} }

379
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "0a35f14eff2d93998449dc614f02d610", "content-hash": "dc72ee68996f3f738763eafd350bc0e0",
"packages": [ "packages": [
{ {
"name": "api-platform/doctrine-common", "name": "api-platform/doctrine-common",
@@ -5841,6 +5841,82 @@
], ],
"time": "2026-03-06T13:17:40+00:00" "time": "2026-03-06T13:17:40+00:00"
}, },
{
"name": "symfony/doctrine-messenger",
"version": "v8.0.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/doctrine-messenger.git",
"reference": "88329a3faba5023cfb569b3fc5b8a771336c4a88"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/doctrine-messenger/zipball/88329a3faba5023cfb569b3fc5b8a771336c4a88",
"reference": "88329a3faba5023cfb569b3fc5b8a771336c4a88",
"shasum": ""
},
"require": {
"doctrine/dbal": "^4.3",
"php": ">=8.4",
"symfony/messenger": "^7.4|^8.0",
"symfony/service-contracts": "^2.5|^3"
},
"conflict": {
"doctrine/persistence": "<1.3"
},
"require-dev": {
"doctrine/persistence": "^1.3|^2|^3",
"symfony/property-access": "^7.4|^8.0",
"symfony/serializer": "^7.4|^8.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/v8.0.6"
},
"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-02-20T07:51:53+00:00"
},
{ {
"name": "symfony/dotenv", "name": "symfony/dotenv",
"version": "v8.0.7", "version": "v8.0.7",
@@ -7099,6 +7175,96 @@
], ],
"time": "2026-03-04T16:39:24+00:00" "time": "2026-03-04T16:39:24+00:00"
}, },
{
"name": "symfony/messenger",
"version": "v8.0.11",
"source": {
"type": "git",
"url": "https://github.com/symfony/messenger.git",
"reference": "c451c175724fc781c777783aaec3b7999ceb0621"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/messenger/zipball/c451c175724fc781c777783aaec3b7999ceb0621",
"reference": "c451c175724fc781c777783aaec3b7999ceb0621",
"shasum": ""
},
"require": {
"php": ">=8.4",
"psr/log": "^1|^2|^3",
"symfony/clock": "^7.4|^8.0"
},
"conflict": {
"symfony/console": "<7.4",
"symfony/event-dispatcher-contracts": "<2.5",
"symfony/lock": "<7.4",
"symfony/serializer": "<7.4.4|>=8.0,<8.0.4"
},
"require-dev": {
"psr/cache": "^1.0|^2.0|^3.0",
"symfony/console": "^7.4|^8.0",
"symfony/dependency-injection": "^7.4|^8.0",
"symfony/event-dispatcher": "^7.4|^8.0",
"symfony/http-kernel": "^7.4|^8.0",
"symfony/lock": "^7.4|^8.0",
"symfony/process": "^7.4|^8.0",
"symfony/property-access": "^7.4|^8.0",
"symfony/rate-limiter": "^7.4|^8.0",
"symfony/routing": "^7.4|^8.0",
"symfony/serializer": "^7.4.4|^8.0.4",
"symfony/service-contracts": "^2.5|^3",
"symfony/stopwatch": "^7.4|^8.0",
"symfony/validator": "^7.4|^8.0",
"symfony/var-dumper": "^7.4|^8.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/v8.0.11"
},
"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-05-13T12:07:53+00:00"
},
{ {
"name": "symfony/mime", "name": "symfony/mime",
"version": "v8.0.7", "version": "v8.0.7",
@@ -13128,6 +13294,217 @@
], ],
"time": "2024-10-20T05:08:20+00:00" "time": "2024-10-20T05:08:20+00:00"
}, },
{
"name": "symfony/browser-kit",
"version": "v8.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
"reference": "f5a28fca785416cf489dd579011e74c831100cc3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/f5a28fca785416cf489dd579011e74c831100cc3",
"reference": "f5a28fca785416cf489dd579011e74c831100cc3",
"shasum": ""
},
"require": {
"php": ">=8.4",
"symfony/dom-crawler": "^7.4|^8.0"
},
"require-dev": {
"symfony/css-selector": "^7.4|^8.0",
"symfony/http-client": "^7.4|^8.0",
"symfony/mime": "^7.4|^8.0",
"symfony/process": "^7.4|^8.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\BrowserKit\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/browser-kit/tree/v8.0.8"
},
"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-03-30T15:14:47+00:00"
},
{
"name": "symfony/css-selector",
"version": "v8.0.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
"reference": "3665cfade90565430909b906394c73c8739e57d0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/3665cfade90565430909b906394c73c8739e57d0",
"reference": "3665cfade90565430909b906394c73c8739e57d0",
"shasum": ""
},
"require": {
"php": ">=8.4"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\CssSelector\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Jean-François Simon",
"email": "jeanfrancois.simon@sensiolabs.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Converts CSS selectors to XPath expressions",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/css-selector/tree/v8.0.9"
},
"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-04-18T13:51:42+00:00"
},
{
"name": "symfony/dom-crawler",
"version": "v8.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
"reference": "284ace90732b445b027728b5e0eec6418a17a364"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/284ace90732b445b027728b5e0eec6418a17a364",
"reference": "284ace90732b445b027728b5e0eec6418a17a364",
"shasum": ""
},
"require": {
"php": ">=8.4",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.0"
},
"require-dev": {
"symfony/css-selector": "^7.4|^8.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\DomCrawler\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Eases DOM navigation for HTML and XML documents",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/dom-crawler/tree/v8.0.8"
},
"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-03-30T15:14:47+00:00"
},
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v8.0.5", "version": "v8.0.5",

View File

@@ -0,0 +1,6 @@
framework:
messenger:
transports:
sync: 'sync://'
routing: {}

View File

@@ -301,7 +301,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* }, * },
* }, * },
* translator?: bool|array{ // Translator configuration * translator?: bool|array{ // Translator configuration
* enabled?: bool|Param, // Default: false * enabled?: bool|Param, // Default: true
* fallbacks?: list<scalar|Param|null>, * fallbacks?: list<scalar|Param|null>,
* logging?: bool|Param, // Default: false * logging?: bool|Param, // Default: false
* formatter?: scalar|Param|null, // Default: "translator.formatter.default" * formatter?: scalar|Param|null, // Default: "translator.formatter.default"
@@ -413,7 +413,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* enabled?: bool|Param, // Default: true * enabled?: bool|Param, // Default: true
* }, * },
* lock?: bool|string|array{ // Lock configuration * lock?: bool|string|array{ // Lock configuration
* enabled?: bool|Param, // Default: false * enabled?: bool|Param, // Default: true
* resources?: array<string, string|list<scalar|Param|null>>, * resources?: array<string, string|list<scalar|Param|null>>,
* }, * },
* semaphore?: bool|string|array{ // Semaphore configuration * semaphore?: bool|string|array{ // Semaphore configuration
@@ -421,7 +421,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* resources?: array<string, scalar|Param|null>, * resources?: array<string, scalar|Param|null>,
* }, * },
* messenger?: bool|array{ // Messenger configuration * messenger?: bool|array{ // Messenger configuration
* enabled?: bool|Param, // Default: false * enabled?: bool|Param, // Default: true
* routing?: array<string, string|array{ // Default: [] * routing?: array<string, string|array{ // Default: []
* senders?: list<scalar|Param|null>, * senders?: list<scalar|Param|null>,
* }>, * }>,
@@ -1360,7 +1360,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* include_type?: bool|Param, // Always include @var in updates (including delete ones). // Default: false * include_type?: bool|Param, // Always include @var in updates (including delete ones). // Default: false
* }, * },
* messenger?: bool|array{ * messenger?: bool|array{
* enabled?: bool|Param, // Default: false * enabled?: bool|Param, // Default: true
* }, * },
* elasticsearch?: bool|array{ * elasticsearch?: bool|array{
* enabled?: bool|Param, // Default: false * enabled?: bool|Param, // Default: false

View File

@@ -22,6 +22,12 @@
<!-- postgresql+advisory://db_user:db_password@localhost/db_name --> <!-- postgresql+advisory://db_user:db_password@localhost/db_name -->
<env name="LOCK_DSN" value="flock"/> <env name="LOCK_DSN" value="flock"/>
<!-- ###- symfony/lock ### --> <!-- ###- symfony/lock ### -->
<!-- ###+ symfony/messenger ### -->
<env name="MESSENGER_TRANSPORT_DSN" value="doctrine://default?auto_setup=0"/>
<!-- ###- symfony/messenger ### -->
<env name="ENCRYPTION_KEY" value="ccd250183ea853179562d458e645585f3d46ddebb0701743236196f60fc1a0b8"/>
</php> </php>
<testsuites> <testsuites>

View File

@@ -47,12 +47,8 @@ use Symfony\Component\Validator\Constraints as Assert;
order: ['createdAt' => 'DESC'], order: ['createdAt' => 'DESC'],
)] )]
#[ORM\Entity(repositoryClass: ClientTicketRepository::class)] #[ORM\Entity(repositoryClass: ClientTicketRepository::class)]
#[ORM\Table( #[ORM\Table(name: 'client_ticket')]
name: 'client_ticket', #[ORM\UniqueConstraint(name: 'uniq_client_ticket_project_number', columns: ['project_id', 'number'])]
uniqueConstraints: [
new ORM\UniqueConstraint(name: 'uniq_client_ticket_project_number', columns: ['project_id', 'number']),
],
)]
class ClientTicket class ClientTicket
{ {
public const string TYPE_BUG = 'bug'; public const string TYPE_BUG = 'bug';