From 64c7be2c20d212acf0c789f058f7eb34fa6cfe2e Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 7 Jan 2025 11:37:40 +0100 Subject: [PATCH 01/76] Add OpenSSL ini config for PHP with custom cafile path --- docker-compose.yml | 2 ++ docker/php/conf.d/openssl.ini | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 docker/php/conf.d/openssl.ini diff --git a/docker-compose.yml b/docker-compose.yml index 8bfe002..7d55f61 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,6 +7,8 @@ services: container_name: goteo-v4-php volumes: - .:/app + - ./docker/php/ssl/ca-bundle.crt:/etc/ssl/ca-bundle.crt:ro + - ./docker/php/conf.d/openssl.ini:/usr/local/etc/php/conf.d/openssl.ini:ro - ./docker/php/conf.d/opcache.ini:/usr/local/etc/php/conf.d/opcache.ini:ro nginx: diff --git a/docker/php/conf.d/openssl.ini b/docker/php/conf.d/openssl.ini new file mode 100644 index 0000000..ae9008c --- /dev/null +++ b/docker/php/conf.d/openssl.ini @@ -0,0 +1,2 @@ +[openssl] +openssl.cafile=/etc/ssl/ca-bundle.crt From d560aa748c95bdebf1870927ceb60137d11be172 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 7 Jan 2025 11:43:05 +0100 Subject: [PATCH 02/76] Ignore ca file, to be downloaded from the internet on docker build --- docker/php/ssl/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 docker/php/ssl/.gitignore diff --git a/docker/php/ssl/.gitignore b/docker/php/ssl/.gitignore new file mode 100644 index 0000000..ea26ec0 --- /dev/null +++ b/docker/php/ssl/.gitignore @@ -0,0 +1 @@ +ca-bundle.crt From 1b28422b3307d3b9cbf1706d3d10da9c0a063499 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 7 Jan 2025 11:49:56 +0100 Subject: [PATCH 03/76] Update README --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d7e7f9e..2a1371f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # The v4 API This repository holds the code for the Goteo **v4** API. +> **NOTE**: Review the trusted certificates by OpenSSL. See: https://github.com/GoteoFoundation/v4/issues/43 + ## Installation This application requires [Docker](https://docs.docker.com/get-docker/) and the [Docker Compose](https://docs.docker.com/compose/install/) plugin. @@ -31,7 +33,7 @@ UID=1001 GID=1001 APP_HTTP_PORT=8080 -APP_HTTPS_PORT=8433 +APP_HTTPS_PORT=8443 ``` Then feed your custom env vars to Compose: @@ -41,7 +43,7 @@ docker compose --env-file .env.local up -d --build - Option B. Passing the variables through the shell. ```shell -export APP_HTTP_PORT=8080 && export APP_HTTPS_PORT=8433 +export APP_HTTP_PORT=8080 && export APP_HTTPS_PORT=8443 # Dynamic user and group id export UID=$(id -u) && export GID=$(id -g) @@ -73,7 +75,7 @@ bin/docker php bin/console app:gateways:setup ## Usage -The app should be live at [http://localhost:8091](http://localhost:8091) (or your specified ports). Keep in mind that the API address is [/v4](http://localhost:8091/v4). +The app should be live at [http://localhost:8090](http://localhost:8090) (or your specified ports). Keep in mind that the API address is [/v4](http://localhost:8090/v4). You can access a real-time build of the OpenAPI spec file for v4 at [http://localhost:8090/v4/docs.json](http://localhost:8090/v4/docs.json), to be used, for example, with API development suites such as Hoppscotch. This file will be up to date with most of your latest changes. @@ -83,6 +85,7 @@ For quick Docker access you can use the `bin/docker` shortcut to quickly `exec` - Login to mysql CLI: `bin/docker mariadb mysql -u goteo -pgoteo goteo` - Debug the symfony services: `bin/docker php bin/console debug:container` +- List app custom commands: `bin/docker php bin/console list app` ## Testing From a6e50a49aa9ba25dc688fab5431f29a18cda4996 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 9 Jan 2025 10:06:16 +0100 Subject: [PATCH 04/76] Add APCu cache layer on Dockerfile base step --- docker/php/Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index decc4a9..2e44084 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -17,6 +17,10 @@ RUN docker-php-ext-install \ intl \ zip +RUN apk --no-cache add $PHPIZE_DEPS +RUN pecl install apcu \ + && docker-php-ext-enable apcu + COPY --from=composer:lts /usr/bin/composer /usr/local/bin/composer From 41be434bbf7a59ef801c57b81dee3121421d0c3b Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 9 Jan 2025 10:11:02 +0100 Subject: [PATCH 05/76] Move opcache from dev to base --- docker/php/Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index 2e44084..3e15038 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -17,17 +17,16 @@ RUN docker-php-ext-install \ intl \ zip +RUN docker-php-ext-install opcache + RUN apk --no-cache add $PHPIZE_DEPS RUN pecl install apcu \ && docker-php-ext-enable apcu COPY --from=composer:lts /usr/bin/composer /usr/local/bin/composer - FROM base AS dev -RUN docker-php-ext-install opcache - RUN apk --no-cache add $PHPIZE_DEPS RUN pecl install xdebug \ && docker-php-ext-enable xdebug From 7ef73cbd10955addc5ce73c803648454c414942b Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 9 Jan 2025 12:24:18 +0100 Subject: [PATCH 06/76] Enable translatable extension --- config/packages/doctrine.yaml | 6 +++++- config/packages/stof_doctrine_extensions.yaml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index f03a88d..688003c 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -22,7 +22,11 @@ doctrine: dir: '%kernel.project_dir%/src/Entity' prefix: 'App\Entity' alias: App - + gedmo_translatable: + type: attribute + prefix: Gedmo\Translatable\Entity + dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Translatable/Entity" + is_bundle: false gedmo_loggable: type: attribute prefix: Gedmo\Loggable\Entity diff --git a/config/packages/stof_doctrine_extensions.yaml b/config/packages/stof_doctrine_extensions.yaml index bd78c6a..a59c282 100644 --- a/config/packages/stof_doctrine_extensions.yaml +++ b/config/packages/stof_doctrine_extensions.yaml @@ -2,8 +2,8 @@ # See the official DoctrineExtensions documentation for more details: https://github.com/doctrine-extensions/DoctrineExtensions/tree/main/doc stof_doctrine_extensions: default_locale: en_US - orm: default: + translatable: true loggable: true timestampable: true From b5366d361324e2238e4951405abbe2290349c271 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 9 Jan 2025 14:36:05 +0100 Subject: [PATCH 07/76] Add request language listener to set locale based on language headers --- src/EventListener/RequestLanguageListener.php | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/EventListener/RequestLanguageListener.php diff --git a/src/EventListener/RequestLanguageListener.php b/src/EventListener/RequestLanguageListener.php new file mode 100644 index 0000000..062e899 --- /dev/null +++ b/src/EventListener/RequestLanguageListener.php @@ -0,0 +1,21 @@ +getRequest(); + + $contentLanguage = $request->headers->get('Content-Language'); + if ($contentLanguage !== null) { + $request->setLocale($contentLanguage); + } + } +} From 0b4d127806f44787c0373733aea539977fabc9aa Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 9 Jan 2025 14:45:05 +0100 Subject: [PATCH 08/76] Basic localized entity content processing --- .../Interface/LocalizedContentInterface.php | 8 ++++++++ src/Entity/Trait/LocalizedContent.php | 16 ++++++++++++++++ src/State/EntityStateProcessor.php | 5 +++++ 3 files changed, 29 insertions(+) create mode 100644 src/Entity/Interface/LocalizedContentInterface.php create mode 100644 src/Entity/Trait/LocalizedContent.php diff --git a/src/Entity/Interface/LocalizedContentInterface.php b/src/Entity/Interface/LocalizedContentInterface.php new file mode 100644 index 0000000..08f22e4 --- /dev/null +++ b/src/Entity/Interface/LocalizedContentInterface.php @@ -0,0 +1,8 @@ +locale = $locale; + } +} diff --git a/src/State/EntityStateProcessor.php b/src/State/EntityStateProcessor.php index 6cbe456..47c32db 100644 --- a/src/State/EntityStateProcessor.php +++ b/src/State/EntityStateProcessor.php @@ -7,6 +7,7 @@ use ApiPlatform\Doctrine\Common\State\RemoveProcessor; use ApiPlatform\Metadata\DeleteOperationInterface; use ApiPlatform\Metadata\Operation; use ApiPlatform\State\ProcessorInterface; +use App\Entity\Interface\LocalizedContentInterface; use Symfony\Component\DependencyInjection\Attribute\Autowire; class EntityStateProcessor implements ProcessorInterface @@ -23,6 +24,10 @@ class EntityStateProcessor implements ProcessorInterface */ public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []) { + if ($data instanceof LocalizedContentInterface) { + $data->setTranslatableLocale($context['request']->getLocale()); + } + if ($operation instanceof DeleteOperationInterface) { return $this->deleteProcessor->process($data, $operation, $uriVariables, $context); } From e8095cccdca90667098729dbc6685c7cc394c7dc Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 9 Jan 2025 14:45:19 +0100 Subject: [PATCH 09/76] Make project titles translatable --- src/Entity/Project/Project.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Entity/Project/Project.php b/src/Entity/Project/Project.php index 2487053..246e919 100644 --- a/src/Entity/Project/Project.php +++ b/src/Entity/Project/Project.php @@ -4,7 +4,9 @@ namespace App\Entity\Project; use App\Entity\Accounting\Accounting; use App\Entity\Interface\AccountingOwnerInterface; +use App\Entity\Interface\LocalizedContentInterface; use App\Entity\Interface\UserOwnedInterface; +use App\Entity\Trait\LocalizedContent; use App\Entity\Trait\MigratedEntity; use App\Entity\Trait\TimestampedCreationEntity; use App\Entity\Trait\TimestampedUpdationEntity; @@ -15,11 +17,13 @@ use AutoMapper\Attribute\MapProvider; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Gedmo\Mapping\Annotation as Gedmo; #[MapProvider(EntityMapProvider::class)] #[ORM\Entity(repositoryClass: ProjectRepository::class)] -class Project implements UserOwnedInterface, AccountingOwnerInterface +class Project implements UserOwnedInterface, AccountingOwnerInterface, LocalizedContentInterface { + use LocalizedContent; use MigratedEntity; use TimestampedCreationEntity; use TimestampedUpdationEntity; @@ -33,6 +37,7 @@ class Project implements UserOwnedInterface, AccountingOwnerInterface * The main title for the project. */ #[ORM\Column(length: 255)] + #[Gedmo\Translatable()] private ?string $title = null; /** From 0fbbdb111237437129bb6b01ada5846120cc05d6 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 9 Jan 2025 14:54:06 +0100 Subject: [PATCH 10/76] Add doctrine extension to hint to localized translations --- src/Doctrine/LocalizedContentExtension.php | 82 ++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 src/Doctrine/LocalizedContentExtension.php diff --git a/src/Doctrine/LocalizedContentExtension.php b/src/Doctrine/LocalizedContentExtension.php new file mode 100644 index 0000000..4dd17c5 --- /dev/null +++ b/src/Doctrine/LocalizedContentExtension.php @@ -0,0 +1,82 @@ +implementsInterface(LocalizedContentInterface::class); + } + + private function addHints(Query $query, string $locale) + { + $query->setHint( + Query::HINT_CUSTOM_OUTPUT_WALKER, + 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' + ); + + $query->setHint( + TranslatableListener::HINT_TRANSLATABLE_LOCALE, + $locale + ); + + $query->setHint( + TranslatableListener::HINT_FALLBACK, + 1 + ); + + $query->getResult(); + } + + public function applyToItem( + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + string $resourceClass, + array $identifiers, + ?Operation $operation = null, + array $context = [] + ): void { + if (!$this->supports($resourceClass)) { + return; + } + + $this->addHints( + $queryBuilder->getQuery(), + $this->requestStack->getCurrentRequest()->getLocale() + ); + } + + public function applyToCollection( + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + string $resourceClass, + ?Operation $operation = null, + array $context = [] + ): void { + if (!$this->supports($resourceClass)) { + return; + } + + $this->addHints( + $queryBuilder->getQuery(), + $this->requestStack->getCurrentRequest()->getLocale() + ); + } +} From 2e6ff5a3bb266a9c66823fa69fecaf09846e6112 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 9 Jan 2025 14:56:23 +0100 Subject: [PATCH 11/76] Retrieve locale from accept-language request header --- src/EventListener/RequestLanguageListener.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/EventListener/RequestLanguageListener.php b/src/EventListener/RequestLanguageListener.php index 062e899..5b29a6e 100644 --- a/src/EventListener/RequestLanguageListener.php +++ b/src/EventListener/RequestLanguageListener.php @@ -9,6 +9,11 @@ use Symfony\Component\HttpKernel\KernelEvents; #[AsEventListener(event: KernelEvents::REQUEST, method: 'processLanguage', priority: 101)] final class RequestLanguageListener { + /** + * Sets the request locale from language headers + * - `Content-Language` for write requests + * - `Accept-Language` for read requests + */ public function processLanguage(RequestEvent $event): void { $request = $event->getRequest(); @@ -17,5 +22,10 @@ final class RequestLanguageListener if ($contentLanguage !== null) { $request->setLocale($contentLanguage); } + + $acceptLanguage = $request->headers->get('Accept-Language'); + if ($acceptLanguage !== null) { + $request->setLocale($acceptLanguage); + } } } From d7656bcaa415a2e690f9e93189998cda9c7402da Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 9 Jan 2025 15:36:38 +0100 Subject: [PATCH 12/76] Store available content locales --- .../Project/ProjectApiResource.php | 8 ++++++ .../Interface/LocalizedContentInterface.php | 6 +++++ src/Entity/Trait/LocalizedContent.php | 25 +++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/src/ApiResource/Project/ProjectApiResource.php b/src/ApiResource/Project/ProjectApiResource.php index 235bb21..2c2b4e3 100644 --- a/src/ApiResource/Project/ProjectApiResource.php +++ b/src/ApiResource/Project/ProjectApiResource.php @@ -44,6 +44,14 @@ class ProjectApiResource #[API\ApiProperty(writable: false)] public UserApiResource $owner; + /** + * List of the available content locales. + * + * @var array + */ + #[API\ApiProperty(writable: false)] + public array $locales; + /** * Main title for the Project. */ diff --git a/src/Entity/Interface/LocalizedContentInterface.php b/src/Entity/Interface/LocalizedContentInterface.php index 08f22e4..0f20e79 100644 --- a/src/Entity/Interface/LocalizedContentInterface.php +++ b/src/Entity/Interface/LocalizedContentInterface.php @@ -5,4 +5,10 @@ namespace App\Entity\Interface; interface LocalizedContentInterface { public function setTranslatableLocale(string $locale); + + public function getLocales(): array; + + public function addLocale(string $locale): static; + + public function setLocales(array $locales): static; } diff --git a/src/Entity/Trait/LocalizedContent.php b/src/Entity/Trait/LocalizedContent.php index 5e30495..e2c9628 100644 --- a/src/Entity/Trait/LocalizedContent.php +++ b/src/Entity/Trait/LocalizedContent.php @@ -2,6 +2,7 @@ namespace App\Entity\Trait; +use Doctrine\ORM\Mapping as ORM; use Gedmo\Mapping\Annotation as Gedmo; trait LocalizedContent @@ -9,8 +10,32 @@ trait LocalizedContent #[Gedmo\Locale] private ?string $locale = null; + #[ORM\Column()] + private array $locales = []; + public function setTranslatableLocale(string $locale) { $this->locale = $locale; + + $this->addLocale($locale); + } + + public function getLocales(): array + { + return $this->locales; + } + + public function addLocale(string $locale): static + { + $this->locales = \array_unique([...$this->locales, $locale]); + + return $this; + } + + public function setLocales(array $locales): static + { + $this->locales = $locales; + + return $this; } } From 6d4f5ad14317dc3e5713d3f4976bcc279ec76f0a Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 9 Jan 2025 15:38:29 +0100 Subject: [PATCH 13/76] Add section about content negotiation for localized content --- src/OpenApi/OpenApiDescription.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/OpenApi/OpenApiDescription.md b/src/OpenApi/OpenApiDescription.md index 65b6f33..b6f6ca5 100644 --- a/src/OpenApi/OpenApiDescription.md +++ b/src/OpenApi/OpenApiDescription.md @@ -12,9 +12,9 @@ This API is still in early development and is not set to have backward compatibi # Authentication -The v4 API uses Access Tokens to authenticate requests. To use a Token, include it in the Authorization header using the [Bearer](https://swagger.io/docs/specification/authentication/bearer-authentication/) strategy. +The v4 API uses Access Tokens to authenticate requests. To use a Token, include it in the `Authorization` header using the [Bearer](https://swagger.io/docs/specification/authentication/bearer-authentication/) strategy. -```shell +```sh curl -X 'GET' \ 'https://api.goteo.org/v4/projects?page=1' \ -H 'accept: application/json' \ @@ -26,3 +26,11 @@ UserTokens exist under an User's scope, when you obtain a token this will only g To obtain a UserToken you must send a POST request to [/v4/user_tokens](/v4/user_tokens) with the User login credentials (username and password) in the payload. If the credentials are correct a UserToken will be created, the `token` property value of which you must include in future requests. Users can delete UserTokens owned by them at any moment, revoking your application's access to the v4 API on their behalf. When a UserToken fails to authenticate a request you will receive a 401 Unauthorized response from the API, at which point your application must look to get a new UserToken from the User. + +# Localization + +The v4 API accepts [Content negotiation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation) for localized content. Resources such as Projects can have owner-submitted content (title, description, etc) in different languages, the extent of which is subject to the owner. + +Retrieval of content in different locales is performed via standard HTTP content negotiation. When the request supplies an `Accept-Language` header, the API will retrieve localized versions of the content when available. Resources with localized content versions will expose a `locales` property listing the available options. + +Aditionally the `Content-Language` header can also be used to set the desired locale, mainly for write requests where you wish to supply a localized version of the working resource. The API will save the localized content under the respective locale without overwriting previous content for other localized versions of the same resource. From 16d56294a53b036234d67d1fd15ab15ab8d54fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Ig=C3=B3n?= Date: Thu, 9 Jan 2025 15:59:59 +0100 Subject: [PATCH 14/76] add command to download cacert.pem --- docker/php/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index decc4a9..9c3adba 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -19,6 +19,8 @@ RUN docker-php-ext-install \ COPY --from=composer:lts /usr/bin/composer /usr/local/bin/composer +RUN curl --remote-name https://curl.se/ca/cacert.pem \ + && mv cacert.pem /etc/ssl/certs/ca-certificates.crt FROM base AS dev From 9928a38b98f559cef6bf8f4009193b93e87b6b16 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 9 Jan 2025 16:02:39 +0100 Subject: [PATCH 15/76] Code quality improvements --- .../Project/ProjectApiResource.php | 2 +- src/Doctrine/LocalizedContentExtension.php | 11 ++++++--- .../Interface/LocalizedContentInterface.php | 23 ++++++++++++++++++- src/EventListener/RequestLanguageListener.php | 2 +- src/State/EntityStateProcessor.php | 2 +- 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/ApiResource/Project/ProjectApiResource.php b/src/ApiResource/Project/ProjectApiResource.php index 2c2b4e3..4e5d485 100644 --- a/src/ApiResource/Project/ProjectApiResource.php +++ b/src/ApiResource/Project/ProjectApiResource.php @@ -46,7 +46,7 @@ class ProjectApiResource /** * List of the available content locales. - * + * * @var array */ #[API\ApiProperty(writable: false)] diff --git a/src/Doctrine/LocalizedContentExtension.php b/src/Doctrine/LocalizedContentExtension.php index 4dd17c5..902c99b 100644 --- a/src/Doctrine/LocalizedContentExtension.php +++ b/src/Doctrine/LocalizedContentExtension.php @@ -4,14 +4,19 @@ namespace App\Doctrine; use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface; use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface; -use Doctrine\ORM\QueryBuilder; use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Metadata\Operation; use App\Entity\Interface\LocalizedContentInterface; use Doctrine\ORM\Query; +use Doctrine\ORM\QueryBuilder; use Gedmo\Translatable\TranslatableListener; use Symfony\Component\HttpFoundation\RequestStack; +/** + * Adds localization hints to translatable entity queries. + * + * @see https://github.com/doctrine-extensions/DoctrineExtensions/blob/main/doc/translatable.md#using-orm-query-hint + */ final class LocalizedContentExtension implements QueryItemExtensionInterface, QueryCollectionExtensionInterface { public function __construct( @@ -51,7 +56,7 @@ final class LocalizedContentExtension implements QueryItemExtensionInterface, Qu string $resourceClass, array $identifiers, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { if (!$this->supports($resourceClass)) { return; @@ -68,7 +73,7 @@ final class LocalizedContentExtension implements QueryItemExtensionInterface, Qu QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { if (!$this->supports($resourceClass)) { return; diff --git a/src/Entity/Interface/LocalizedContentInterface.php b/src/Entity/Interface/LocalizedContentInterface.php index 0f20e79..4ae11c3 100644 --- a/src/Entity/Interface/LocalizedContentInterface.php +++ b/src/Entity/Interface/LocalizedContentInterface.php @@ -2,13 +2,34 @@ namespace App\Entity\Interface; -interface LocalizedContentInterface +use Gedmo\Translatable\Translatable; + +/** + * Provides an advanced way to work with Translatable entities. + * + * {@inheritdoc} + * + * @see https://github.com/doctrine-extensions/DoctrineExtensions/blob/main/doc/translatable.md#translatable-behavior-extension-for-doctrine + */ +interface LocalizedContentInterface extends Translatable { + /** + * Set the locale of the working content for translations. + */ public function setTranslatableLocale(string $locale); + /** + * Obtain a list of the available locales to query translations of the entity. + */ public function getLocales(): array; + /** + * Add to the list of available translation locales. + */ public function addLocale(string $locale): static; + /** + * Set the list of available translation locales. + */ public function setLocales(array $locales): static; } diff --git a/src/EventListener/RequestLanguageListener.php b/src/EventListener/RequestLanguageListener.php index 5b29a6e..cd123f3 100644 --- a/src/EventListener/RequestLanguageListener.php +++ b/src/EventListener/RequestLanguageListener.php @@ -12,7 +12,7 @@ final class RequestLanguageListener /** * Sets the request locale from language headers * - `Content-Language` for write requests - * - `Accept-Language` for read requests + * - `Accept-Language` for read requests. */ public function processLanguage(RequestEvent $event): void { diff --git a/src/State/EntityStateProcessor.php b/src/State/EntityStateProcessor.php index 47c32db..75c8949 100644 --- a/src/State/EntityStateProcessor.php +++ b/src/State/EntityStateProcessor.php @@ -27,7 +27,7 @@ class EntityStateProcessor implements ProcessorInterface if ($data instanceof LocalizedContentInterface) { $data->setTranslatableLocale($context['request']->getLocale()); } - + if ($operation instanceof DeleteOperationInterface) { return $this->deleteProcessor->process($data, $operation, $uriVariables, $context); } From 7faaadeadc78e9a1e303007697a346532e2796f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Ig=C3=B3n?= Date: Thu, 9 Jan 2025 19:02:46 +0100 Subject: [PATCH 16/76] change cafile route in openssl.ini --- docker/php/conf.d/openssl.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/php/conf.d/openssl.ini b/docker/php/conf.d/openssl.ini index ae9008c..e1b00fa 100644 --- a/docker/php/conf.d/openssl.ini +++ b/docker/php/conf.d/openssl.ini @@ -1,2 +1,2 @@ [openssl] -openssl.cafile=/etc/ssl/ca-bundle.crt +openssl.cafile=/etc/ssl/certs/ca-certificates.crt From e413e7c02352a09a2939d475fa8a4f89f9f0c67f Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 09:21:24 +0100 Subject: [PATCH 17/76] Move test certificates volume to override config --- docker-compose.override.yml | 1 + docker-compose.yml | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 5c29684..a776fbc 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -1,6 +1,7 @@ services: php: volumes: + # ./docker/php/ssl/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro - ./docker/php/conf.d/opcache.dev.ini:/usr/local/etc/php/conf.d/opcache.ini:ro - ./docker/php/conf.d/xdebug.dev.ini:/usr/local/etc/php/conf.d/xdebug.ini:ro extra_hosts: diff --git a/docker-compose.yml b/docker-compose.yml index 7d55f61..c1f6ba8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,6 @@ services: container_name: goteo-v4-php volumes: - .:/app - - ./docker/php/ssl/ca-bundle.crt:/etc/ssl/ca-bundle.crt:ro - ./docker/php/conf.d/openssl.ini:/usr/local/etc/php/conf.d/openssl.ini:ro - ./docker/php/conf.d/opcache.ini:/usr/local/etc/php/conf.d/opcache.ini:ro From dad48ca65b80a224c393471b763798e4aa018a91 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 09:22:04 +0100 Subject: [PATCH 18/76] Ignore every crt file in docker/php/ssl --- docker/php/ssl/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/php/ssl/.gitignore b/docker/php/ssl/.gitignore index ea26ec0..a4e94ec 100644 --- a/docker/php/ssl/.gitignore +++ b/docker/php/ssl/.gitignore @@ -1 +1 @@ -ca-bundle.crt +*.crt From d73cf43f1bbdc34b9dd058a8d033496c880aa081 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 09:51:38 +0100 Subject: [PATCH 19/76] Update localization description --- src/OpenApi/OpenApiDescription.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OpenApi/OpenApiDescription.md b/src/OpenApi/OpenApiDescription.md index b6f6ca5..5138ae3 100644 --- a/src/OpenApi/OpenApiDescription.md +++ b/src/OpenApi/OpenApiDescription.md @@ -29,8 +29,8 @@ Users can delete UserTokens owned by them at any moment, revoking your applicati # Localization -The v4 API accepts [Content negotiation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation) for localized content. Resources such as Projects can have owner-submitted content (title, description, etc) in different languages, the extent of which is subject to the owner. +The v4 API accepts localization of content. Resources such as Projects can have owner-submitted data (title, description, etc) in different languages, the extent of which is subject to the owner. Resources with localized content versions will expose a `locales` property listing the available localizations. -Retrieval of content in different locales is performed via standard HTTP content negotiation. When the request supplies an `Accept-Language` header, the API will retrieve localized versions of the content when available. Resources with localized content versions will expose a `locales` property listing the available options. +Retrieval of content in different locales is performed via standard HTTP [content negotiation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation). When the request supplies an `Accept-Language` header, the API will retrieve localized versions of the content where available, falling back to the default locale of the API instance, and finally to the first available localization of the content regardless of the request preferences or the API defaults if it cannot find suitable localizations. -Aditionally the `Content-Language` header can also be used to set the desired locale, mainly for write requests where you wish to supply a localized version of the working resource. The API will save the localized content under the respective locale without overwriting previous content for other localized versions of the same resource. +Submission of localized content is performed over standard HTTP content submission with the addition of a `Content-Language` header to a POST, PUT or PATCH request. From 8ad789c9998eb48eabcc748ba290406581d2dbeb Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 09:51:50 +0100 Subject: [PATCH 20/76] Use locale from kernel --- config/packages/stof_doctrine_extensions.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/packages/stof_doctrine_extensions.yaml b/config/packages/stof_doctrine_extensions.yaml index a59c282..079ea08 100644 --- a/config/packages/stof_doctrine_extensions.yaml +++ b/config/packages/stof_doctrine_extensions.yaml @@ -1,7 +1,7 @@ # Read the documentation: https://symfony.com/doc/current/bundles/StofDoctrineExtensionsBundle/index.html # See the official DoctrineExtensions documentation for more details: https://github.com/doctrine-extensions/DoctrineExtensions/tree/main/doc stof_doctrine_extensions: - default_locale: en_US + default_locale: '%kernel.default_locale%' orm: default: translatable: true From 6adb2bd43800950afbeee40bbb87e385f9a7954b Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 11:11:19 +0100 Subject: [PATCH 21/76] Add details about localized content submission languages flattening --- src/OpenApi/OpenApiDescription.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenApi/OpenApiDescription.md b/src/OpenApi/OpenApiDescription.md index 5138ae3..f7ff850 100644 --- a/src/OpenApi/OpenApiDescription.md +++ b/src/OpenApi/OpenApiDescription.md @@ -33,4 +33,4 @@ The v4 API accepts localization of content. Resources such as Projects can have Retrieval of content in different locales is performed via standard HTTP [content negotiation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation). When the request supplies an `Accept-Language` header, the API will retrieve localized versions of the content where available, falling back to the default locale of the API instance, and finally to the first available localization of the content regardless of the request preferences or the API defaults if it cannot find suitable localizations. -Submission of localized content is performed over standard HTTP content submission with the addition of a `Content-Language` header to a POST, PUT or PATCH request. +Submission of localized content is performed over standard HTTP content submission with the addition of a `Content-Language` header to a POST, PUT or PATCH request. Localizations are assumed to be one per language globally. Contained tags will be matched to an [ISO 639](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) two-letter code and only the first tag will be used to determine the submitted localization, e.g: a value of "ca_ES, es_ES", for a text primarily in Catalan (ca_ES) and bits in Spanish (es_ES) will be converted to "ca", ignoring the Spanish language tag and the "ES" subtag in "ca_ES". From 6c8f9c9a909dc2e1aa568ef7c505dd1f162333c4 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 11:12:07 +0100 Subject: [PATCH 22/76] Add localization service to help parsing language tags --- config/services.yaml | 4 ++ src/Service/LocalizationService.php | 75 +++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/Service/LocalizationService.php diff --git a/config/services.yaml b/config/services.yaml index 8a6bc90..54bb91e 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -59,6 +59,10 @@ services: arguments: - '%env(APP_SECRET)%' + App\Service\LocalizationService: + arguments: + - '%kernel.default_locale%' + App\Library\Benzina\Benzina: arguments: - !tagged 'app.lib.benzina.pump.pump' diff --git a/src/Service/LocalizationService.php b/src/Service/LocalizationService.php new file mode 100644 index 0000000..0c2ecdf --- /dev/null +++ b/src/Service/LocalizationService.php @@ -0,0 +1,75 @@ +parseLanguageTags($tags)[0]; + + return $this->getPrimaryLanguage($tag); + } + + /** + * @param string $tags A string of language tags + * + * @return array The primary language of the supplied tags + * + * @see https://www.rfc-editor.org/rfc/bcp/bcp47.txt + */ + public function getLanguages(string $tags): array + { + $tags = $this->parseLanguageTags($tags); + + foreach ($tags as $key => $tag) { + $tags[$key] = $this->getPrimaryLanguage($tag); + } + + return $tags; + } + + private function getPrimaryLanguage(string $tag): string + { + $language = \Locale::getPrimaryLanguage($tag); + if ($language === null) { + throw new \Exception(\sprintf(self::ERROR_TAG_INVALID_LANG, $tag)); + } + + if (!\in_array($language, Languages::getLanguageCodes())) { + throw new \Exception(\sprintf(self::ERROR_TAG_INVALID_LANG, $tag)); + } + + return $language; + } + + private function parseLanguageTags(?string $tags = null): array + { + if ($tags === null) { + return [$this->defaultLocale]; + } + + $languages = \array_map('trim', \explode(',', $tags)); + + if (empty($languages)) { + return [$this->defaultLocale]; + } + + return $languages; + } +} From 5c8c4859d94b023319b2693c0e6fb11df3d925a0 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 11:13:10 +0100 Subject: [PATCH 23/76] Use content-language header value for localized resources processing --- src/State/EntityStateProcessor.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/State/EntityStateProcessor.php b/src/State/EntityStateProcessor.php index 75c8949..6c9c564 100644 --- a/src/State/EntityStateProcessor.php +++ b/src/State/EntityStateProcessor.php @@ -8,7 +8,9 @@ use ApiPlatform\Metadata\DeleteOperationInterface; use ApiPlatform\Metadata\Operation; use ApiPlatform\State\ProcessorInterface; use App\Entity\Interface\LocalizedContentInterface; +use App\Service\LocalizationService; use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\HttpFoundation\Request; class EntityStateProcessor implements ProcessorInterface { @@ -17,6 +19,7 @@ class EntityStateProcessor implements ProcessorInterface private ProcessorInterface $deleteProcessor, #[Autowire(service: PersistProcessor::class)] private ProcessorInterface $persistProcessor, + private LocalizationService $localizationService, ) {} /** @@ -25,7 +28,12 @@ class EntityStateProcessor implements ProcessorInterface public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []) { if ($data instanceof LocalizedContentInterface) { - $data->setTranslatableLocale($context['request']->getLocale()); + /** @var Request */ + $request = $context['request']; + + $data->setTranslatableLocale($this->localizationService->getLanguage( + $request->headers->get('Content-Language'), + )); } if ($operation instanceof DeleteOperationInterface) { From c440df9b3a14dad5649cfbdc22e28af9b2c06c19 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 11:19:43 +0100 Subject: [PATCH 24/76] Use accept-language header value localized resources querying --- src/Doctrine/LocalizedContentExtension.php | 67 ++++++++++++---------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/src/Doctrine/LocalizedContentExtension.php b/src/Doctrine/LocalizedContentExtension.php index 902c99b..676fb7b 100644 --- a/src/Doctrine/LocalizedContentExtension.php +++ b/src/Doctrine/LocalizedContentExtension.php @@ -7,6 +7,7 @@ use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface; use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Metadata\Operation; use App\Entity\Interface\LocalizedContentInterface; +use App\Service\LocalizationService; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; use Gedmo\Translatable\TranslatableListener; @@ -21,35 +22,9 @@ final class LocalizedContentExtension implements QueryItemExtensionInterface, Qu { public function __construct( private RequestStack $requestStack, + private LocalizationService $localizationService, ) {} - private function supports(string $resourceClass): bool - { - $reflection = new \ReflectionClass($resourceClass); - - return $reflection->implementsInterface(LocalizedContentInterface::class); - } - - private function addHints(Query $query, string $locale) - { - $query->setHint( - Query::HINT_CUSTOM_OUTPUT_WALKER, - 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' - ); - - $query->setHint( - TranslatableListener::HINT_TRANSLATABLE_LOCALE, - $locale - ); - - $query->setHint( - TranslatableListener::HINT_FALLBACK, - 1 - ); - - $query->getResult(); - } - public function applyToItem( QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, @@ -62,9 +37,11 @@ final class LocalizedContentExtension implements QueryItemExtensionInterface, Qu return; } + $request = $this->requestStack->getCurrentRequest(); + $this->addHints( $queryBuilder->getQuery(), - $this->requestStack->getCurrentRequest()->getLocale() + $this->localizationService->getLanguages($request->headers->get('Accept-Language')) ); } @@ -79,9 +56,41 @@ final class LocalizedContentExtension implements QueryItemExtensionInterface, Qu return; } + $request = $this->requestStack->getCurrentRequest(); + $this->addHints( $queryBuilder->getQuery(), - $this->requestStack->getCurrentRequest()->getLocale() + $this->localizationService->getLanguages($request->headers->get('Accept-Language')) ); } + + private function supports(string $resourceClass): bool + { + $reflection = new \ReflectionClass($resourceClass); + + return $reflection->implementsInterface(LocalizedContentInterface::class); + } + + private function addHints(Query $query, array $locales) + { + $query->setHint( + Query::HINT_CUSTOM_OUTPUT_WALKER, + 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' + ); + + $locales = \array_reverse($locales); + foreach ($locales as $locale) { + $query->setHint( + TranslatableListener::HINT_TRANSLATABLE_LOCALE, + $locale + ); + } + + $query->setHint( + TranslatableListener::HINT_FALLBACK, + 1 + ); + + $query->getResult(); + } } From 7dcb464fe801c3fbd1ed070afeea23a3c95657d8 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 11:48:48 +0100 Subject: [PATCH 25/76] Add testing for localization services --- src/Service/LocalizationService.php | 9 +++- tests/Service/LocalizationServiceTest.php | 54 +++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 tests/Service/LocalizationServiceTest.php diff --git a/src/Service/LocalizationService.php b/src/Service/LocalizationService.php index 0c2ecdf..c53d06d 100644 --- a/src/Service/LocalizationService.php +++ b/src/Service/LocalizationService.php @@ -2,6 +2,7 @@ namespace App\Service; +use Locale; use Symfony\Component\Intl\Languages; class LocalizationService @@ -46,7 +47,7 @@ class LocalizationService private function getPrimaryLanguage(string $tag): string { - $language = \Locale::getPrimaryLanguage($tag); + $language = Locale::getPrimaryLanguage($tag); if ($language === null) { throw new \Exception(\sprintf(self::ERROR_TAG_INVALID_LANG, $tag)); } @@ -64,7 +65,11 @@ class LocalizationService return [$this->defaultLocale]; } - $languages = \array_map('trim', \explode(',', $tags)); + $languages = \array_map(function (string $tag) { + $tag = \explode(';', $tag); + + return \trim($tag[0]); + }, \explode(',', $tags)); if (empty($languages)) { return [$this->defaultLocale]; diff --git a/tests/Service/LocalizationServiceTest.php b/tests/Service/LocalizationServiceTest.php new file mode 100644 index 0000000..e036713 --- /dev/null +++ b/tests/Service/LocalizationServiceTest.php @@ -0,0 +1,54 @@ +localizationService = static::getContainer()->get(LocalizationService::class); + } + + public function testThrowsUnknownLanguageException() + { + $this->expectException(\Exception::class); + + $this->localizationService->getLanguage('*;q=0.5'); + } + + public function testThrowsUnknownLanguageExceptionInTagList() + { + $this->expectException(\Exception::class); + + $this->localizationService->getLanguages('fr-FR, *;q=0.5'); + } + + public function testGetsFirstLanguageFromTags() + { + $language = $this->localizationService->getLanguage(self::TAGS); + + $this->assertEquals('es', $language); + } + + public function testGetsLanguagesFromTags() + { + $languages = $this->localizationService->getLanguages(self::TAGS); + + $this->assertIsArray($languages); + $this->assertCount(4, $languages); + + $this->assertEquals('es', $languages[0]); + $this->assertEquals('es', $languages[1]); + $this->assertEquals('en', $languages[2]); + $this->assertEquals('de', $languages[3]); + } +} From 8d081b832eb944cb184778a8463f09320d701cd8 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 11:53:07 +0100 Subject: [PATCH 26/76] Call Locale class from global namespace --- src/Service/LocalizationService.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Service/LocalizationService.php b/src/Service/LocalizationService.php index c53d06d..9adc359 100644 --- a/src/Service/LocalizationService.php +++ b/src/Service/LocalizationService.php @@ -2,7 +2,6 @@ namespace App\Service; -use Locale; use Symfony\Component\Intl\Languages; class LocalizationService @@ -47,7 +46,7 @@ class LocalizationService private function getPrimaryLanguage(string $tag): string { - $language = Locale::getPrimaryLanguage($tag); + $language = \Locale::getPrimaryLanguage($tag); if ($language === null) { throw new \Exception(\sprintf(self::ERROR_TAG_INVALID_LANG, $tag)); } From f33a98682fed6358110db0014e54e39a024c9cb2 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 12:22:32 +0100 Subject: [PATCH 27/76] Add intl php extension --- .github/workflows/phpunit.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/phpunit.yaml b/.github/workflows/phpunit.yaml index 0122ac8..b576b88 100644 --- a/.github/workflows/phpunit.yaml +++ b/.github/workflows/phpunit.yaml @@ -26,5 +26,5 @@ jobs: DATABASE_URL: mysql://root:goteo@127.0.0.1:${{ job.services.mariadb.ports['3306'] }}/goteo with: php_version: 8.3 - php_extensions: pdo_mysql + php_extensions: pdo_mysql intl configuration: phpunit.xml.dist From 05fedab50673b9d744d9c64ddda0869ba193e9e2 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 12:25:30 +0100 Subject: [PATCH 28/76] Remove request language listener --- src/EventListener/RequestLanguageListener.php | 31 ------------------- 1 file changed, 31 deletions(-) delete mode 100644 src/EventListener/RequestLanguageListener.php diff --git a/src/EventListener/RequestLanguageListener.php b/src/EventListener/RequestLanguageListener.php deleted file mode 100644 index cd123f3..0000000 --- a/src/EventListener/RequestLanguageListener.php +++ /dev/null @@ -1,31 +0,0 @@ -getRequest(); - - $contentLanguage = $request->headers->get('Content-Language'); - if ($contentLanguage !== null) { - $request->setLocale($contentLanguage); - } - - $acceptLanguage = $request->headers->get('Accept-Language'); - if ($acceptLanguage !== null) { - $request->setLocale($acceptLanguage); - } - } -} From 56019a88270a6f21446e3ec78e126e39b85299f8 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 12:46:36 +0100 Subject: [PATCH 29/76] Improve localization service code --- src/Service/LocalizationService.php | 42 +++++++++++++++-------- tests/Service/LocalizationServiceTest.php | 8 +++++ 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/Service/LocalizationService.php b/src/Service/LocalizationService.php index 9adc359..d6ca105 100644 --- a/src/Service/LocalizationService.php +++ b/src/Service/LocalizationService.php @@ -8,22 +8,42 @@ class LocalizationService { public const ERROR_TAG_INVALID_LANG = "The tag '%s' does not match to any language."; + private string $defaultLanguage; + public function __construct( private string $defaultLocale, - ) {} + ) { + $this->defaultLanguage = $this->getPrimaryLanguage($defaultLocale); + } + + public function getDefaultLocale(): string + { + return $this->defaultLocale; + } + + public function getDefaultLanguage(): string + { + return $this->defaultLanguage; + } /** * @param string $tags A string of language tags * - * @return string The primary language of the first supplied tag + * @return string The primary language of the first supplied tag, or the default language if empty + * + * @throws \Exception If the first tag specifies an invalid language * * @see https://www.rfc-editor.org/rfc/bcp/bcp47.txt */ public function getLanguage(string $tags): string { - $tag = $this->parseLanguageTags($tags)[0]; + $tags = $this->parseLanguageTags($tags); - return $this->getPrimaryLanguage($tag); + if (empty($tags[0])) { + return $this->getDefaultLanguage(); + } + + return $this->getPrimaryLanguage($tags[0]); } /** @@ -31,6 +51,8 @@ class LocalizationService * * @return array The primary language of the supplied tags * + * @throws \Exception If one of the supplied tags specifies an invalid language + * * @see https://www.rfc-editor.org/rfc/bcp/bcp47.txt */ public function getLanguages(string $tags): array @@ -58,21 +80,13 @@ class LocalizationService return $language; } - private function parseLanguageTags(?string $tags = null): array + private function parseLanguageTags(string $tagsString): array { - if ($tags === null) { - return [$this->defaultLocale]; - } - $languages = \array_map(function (string $tag) { $tag = \explode(';', $tag); return \trim($tag[0]); - }, \explode(',', $tags)); - - if (empty($languages)) { - return [$this->defaultLocale]; - } + }, \explode(',', $tagsString)); return $languages; } diff --git a/tests/Service/LocalizationServiceTest.php b/tests/Service/LocalizationServiceTest.php index e036713..cbc545f 100644 --- a/tests/Service/LocalizationServiceTest.php +++ b/tests/Service/LocalizationServiceTest.php @@ -39,6 +39,14 @@ class LocalizationServiceTest extends KernelTestCase $this->assertEquals('es', $language); } + public function testReturnsDefaultLocale() + { + $this->assertEquals( + $this->localizationService->getDefaultLanguage(), + $this->localizationService->getLanguage('') + ); + } + public function testGetsLanguagesFromTags() { $languages = $this->localizationService->getLanguages(self::TAGS); From e10064c5a79e7a5d787d310cdefeeaf0c3fa9802 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 10 Jan 2025 13:44:11 +0100 Subject: [PATCH 30/76] Pass empty string if no accept-language header --- src/Doctrine/LocalizedContentExtension.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Doctrine/LocalizedContentExtension.php b/src/Doctrine/LocalizedContentExtension.php index 676fb7b..0c25069 100644 --- a/src/Doctrine/LocalizedContentExtension.php +++ b/src/Doctrine/LocalizedContentExtension.php @@ -41,7 +41,7 @@ final class LocalizedContentExtension implements QueryItemExtensionInterface, Qu $this->addHints( $queryBuilder->getQuery(), - $this->localizationService->getLanguages($request->headers->get('Accept-Language')) + $this->localizationService->getLanguages($request->headers->get('Accept-Language', '')) ); } @@ -60,7 +60,7 @@ final class LocalizedContentExtension implements QueryItemExtensionInterface, Qu $this->addHints( $queryBuilder->getQuery(), - $this->localizationService->getLanguages($request->headers->get('Accept-Language')) + $this->localizationService->getLanguages($request->headers->get('Accept-Language', '')) ); } From c26111565d2000f2a628c8fff60d0f9a086fc5ad Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Mon, 13 Jan 2025 15:04:21 +0100 Subject: [PATCH 31/76] Add localized content provider to add query hints for localizable content --- config/services.yaml | 5 + src/State/LocalizedContentProvider.php | 206 +++++++++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 src/State/LocalizedContentProvider.php diff --git a/config/services.yaml b/config/services.yaml index 54bb91e..978b78f 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -59,6 +59,11 @@ services: arguments: - '%env(APP_SECRET)%' + App\State\LocalizedContentProvider: + arguments: + $itemExtensions: !tagged api_platform.doctrine.orm.query_extension.item + $collectionExtensions: !tagged api_platform.doctrine.orm.query_extension.collection + App\Service\LocalizationService: arguments: - '%kernel.default_locale%' diff --git a/src/State/LocalizedContentProvider.php b/src/State/LocalizedContentProvider.php new file mode 100644 index 0000000..880c689 --- /dev/null +++ b/src/State/LocalizedContentProvider.php @@ -0,0 +1,206 @@ +getClass(); + $entityClass = $this->getEntityClass($operation); + + $manager = $this->managerRegistry->getManagerForClass($entityClass); + + if ($manager === null) { + throw new \RuntimeException(); + } + + $repository = $manager->getRepository($entityClass); + + if (!$repository instanceof EntityRepository) { + throw new \RuntimeException(); + } + + $queryBuilder = $repository->createQueryBuilder('o'); + $queryNameGenerator = new QueryNameGenerator(); + + if ($operation instanceof CollectionOperationInterface) { + $collection = $this->provideCollection($queryBuilder, $queryNameGenerator, $entityClass, $operation, $context); + + $resources = []; + foreach ($collection as $item) { + $resources[] = $this->autoMapper->map($item, $resourceClass); + } + + return new TraversablePaginator( + new \ArrayIterator($resources), + $this->pagination->getPage($context), + $this->pagination->getLimit($operation, $context), + \count($collection) + ); + } + + $item = $this->provideItem($queryBuilder, $queryNameGenerator, $entityClass, $operation, $context); + + if (!$item) { + return null; + } + + return $this->autoMapper->map($item, $resourceClass); + } + + /** + * Determine wether an API operation is localizable or not. + * + * @param Operation $operation The operation as given to the providers + * + * @return bool `true` if the underlying entity is localizable + */ + public function supports(Operation $operation): bool + { + $reflectionClass = new \ReflectionClass($this->getEntityClass($operation)); + + return $reflectionClass->implementsInterface(LocalizedContentInterface::class); + } + + private function getEntityClass(Operation $operation): string + { + /** @var Options */ + $options = $operation->getStateOptions(); + + return $options->getEntityClass(); + } + + /** + * Add a hint for each locale to the query. + * + * @param Query $query The query where the translation hints should be added + * @param string[] $locales A list of the locales to be hinted + * + * @return Query The input query with added hints + * + * @see https://github.com/doctrine-extensions/DoctrineExtensions/blob/main/doc/translatable.md#using-orm-query-hint + */ + private function addTranslatableQueryHints(Query $query, array $locales): Query + { + $query->setHint( + Query::HINT_CUSTOM_OUTPUT_WALKER, + 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' + ); + + $locales = \array_reverse($locales); + foreach ($locales as $locale) { + $query->setHint( + TranslatableListener::HINT_TRANSLATABLE_LOCALE, + $locale + ); + } + + $query->setHint(TranslatableListener::HINT_FALLBACK, 0); + $query->setHint(TranslatableListener::HINT_INNER_JOIN, true); + + return $query; + } + + /** + * @param array|array{request: unset|\Symfony\Component\HttpFoundation\Request, resource_class: unset|string} $context + */ + private function provideCollection( + QueryBuilder $queryBuilder, + QueryNameGenerator $queryNameGenerator, + string $entityClass, + Operation $operation, + array $context = [], + ) { + $queryBuilder + ->setFirstResult($this->pagination->getOffset($operation, $context)) + ->setMaxResults($this->pagination->getLimit($operation, $context)); + + foreach ($this->collectionExtensions as $extension) { + $extension->applyToCollection( + $queryBuilder, + $queryNameGenerator, + $entityClass, + $operation, + $context + ); + } + + $languages = $context['request']->headers->get('Accept-Language', ''); + + $query = $this->addTranslatableQueryHints( + $queryBuilder->getQuery()->useQueryCache(true)->enableResultCache(), + $this->localizationService->getLanguages($languages) + ); + + return $query->getResult(); + } + + /** + * @param array|array{request: unset|\Symfony\Component\HttpFoundation\Request, resource_class: unset|string} $context + */ + private function provideItem( + QueryBuilder $queryBuilder, + QueryNameGenerator $queryNameGenerator, + string $entityClass, + Operation $operation, + array $context = [], + ) { + $rootAlias = $queryBuilder->getRootAliases()[0]; + $queryBuilder->where($queryBuilder->expr()->eq(\sprintf('%s.id', $rootAlias), $context['uri_variables']['id'])); + + foreach ($this->itemExtensions as $extension) { + $extension->applyToItem( + $queryBuilder, + $queryNameGenerator, + $entityClass, + $context['uri_variables'], + $operation, + $context + ); + } + + $languages = $context['request']->headers->get('Accept-Language', ''); + + $query = $this->addTranslatableQueryHints( + $queryBuilder->getQuery()->useQueryCache(true)->enableResultCache(), + $this->localizationService->getLanguages($languages) + ); + + return $query->getOneOrNullResult(); + } +} From b14e172c82976e31ce9f51d22aca775f375c7982 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Mon, 13 Jan 2025 15:04:36 +0100 Subject: [PATCH 32/76] Remove localized content extension --- src/Doctrine/LocalizedContentExtension.php | 96 ---------------------- 1 file changed, 96 deletions(-) delete mode 100644 src/Doctrine/LocalizedContentExtension.php diff --git a/src/Doctrine/LocalizedContentExtension.php b/src/Doctrine/LocalizedContentExtension.php deleted file mode 100644 index 0c25069..0000000 --- a/src/Doctrine/LocalizedContentExtension.php +++ /dev/null @@ -1,96 +0,0 @@ -supports($resourceClass)) { - return; - } - - $request = $this->requestStack->getCurrentRequest(); - - $this->addHints( - $queryBuilder->getQuery(), - $this->localizationService->getLanguages($request->headers->get('Accept-Language', '')) - ); - } - - public function applyToCollection( - QueryBuilder $queryBuilder, - QueryNameGeneratorInterface $queryNameGenerator, - string $resourceClass, - ?Operation $operation = null, - array $context = [], - ): void { - if (!$this->supports($resourceClass)) { - return; - } - - $request = $this->requestStack->getCurrentRequest(); - - $this->addHints( - $queryBuilder->getQuery(), - $this->localizationService->getLanguages($request->headers->get('Accept-Language', '')) - ); - } - - private function supports(string $resourceClass): bool - { - $reflection = new \ReflectionClass($resourceClass); - - return $reflection->implementsInterface(LocalizedContentInterface::class); - } - - private function addHints(Query $query, array $locales) - { - $query->setHint( - Query::HINT_CUSTOM_OUTPUT_WALKER, - 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' - ); - - $locales = \array_reverse($locales); - foreach ($locales as $locale) { - $query->setHint( - TranslatableListener::HINT_TRANSLATABLE_LOCALE, - $locale - ); - } - - $query->setHint( - TranslatableListener::HINT_FALLBACK, - 1 - ); - - $query->getResult(); - } -} From 0f8523cdf0475889d7d3e855d1229cf348cbdc53 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Mon, 13 Jan 2025 15:05:24 +0100 Subject: [PATCH 33/76] Api resource provider usage of localizable provider via injection --- src/State/ApiResourceStateProvider.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/State/ApiResourceStateProvider.php b/src/State/ApiResourceStateProvider.php index 9b41b71..9c26242 100644 --- a/src/State/ApiResourceStateProvider.php +++ b/src/State/ApiResourceStateProvider.php @@ -19,10 +19,15 @@ class ApiResourceStateProvider implements ProviderInterface #[Autowire(service: ItemProvider::class)] private ProviderInterface $itemProvider, private AutoMapper $autoMapper, + private LocalizedContentProvider $localizedContentProvider, ) {} public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null { + if ($this->localizedContentProvider->supports($operation)) { + return $this->localizedContentProvider->provide($operation, $uriVariables, $context); + } + $resourceClass = $operation->getClass(); if ($operation instanceof CollectionOperationInterface) { From ac6cba36da9ac9696c76fbad521cfbbcf0e6b5a2 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 14 Jan 2025 14:22:40 +0100 Subject: [PATCH 34/76] Rescue extension usage to provider localized content versions --- src/Doctrine/LocalizedContentExtension.php | 128 +++++++++++++++++++++ src/Doctrine/PaginationExtensionTrait.php | 109 ++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 src/Doctrine/LocalizedContentExtension.php create mode 100644 src/Doctrine/PaginationExtensionTrait.php diff --git a/src/Doctrine/LocalizedContentExtension.php b/src/Doctrine/LocalizedContentExtension.php new file mode 100644 index 0000000..136e60b --- /dev/null +++ b/src/Doctrine/LocalizedContentExtension.php @@ -0,0 +1,128 @@ +implementsInterface(LocalizedContentInterface::class); + } + + public function getResult( + QueryBuilder $queryBuilder, + ?string $resourceClass = null, + ?Operation $operation = null, + array $context = [] + ): iterable { + $query = $this->addLocalizationHints($queryBuilder, $this->getContextLanguages($context)); + + if (1 === \count($queryBuilder->getAllAliases())) { + $query->setHint(CountWalker::HINT_DISTINCT, false); + } + + $doctrineOrmPaginator = new DoctrineOrmPaginator($query, $this->shouldDoctrinePaginatorFetchJoinCollection($queryBuilder, $operation, $context)); + $doctrineOrmPaginator->setUseOutputWalkers($this->shouldDoctrinePaginatorUseOutputWalkers($queryBuilder, $operation, $context)); + + $isPartialEnabled = $this->pagination->isPartialEnabled($operation, $context); + + if ($isPartialEnabled) { + return new class($doctrineOrmPaginator) extends AbstractPaginator { + }; + } + + return new Paginator($doctrineOrmPaginator); + } + + public function applyToCollection( + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + string $resourceClass, + ?Operation $operation = null, + array $context = [] + ): void { + if (null === $pagination = $this->getPagination($queryBuilder, $operation, $context)) { + return; + } + + [$offset, $limit] = $pagination; + + $queryBuilder + ->setFirstResult($offset) + ->setMaxResults($limit); + } + + /** + * @throws InvalidArgumentException + */ + private function getPagination(QueryBuilder $queryBuilder, ?Operation $operation, array $context): ?array + { + $enabled = isset($context['graphql_operation_name']) ? $this->pagination->isGraphQlEnabled($operation, $context) : $this->pagination->isEnabled($operation, $context); + + if (!$enabled) { + return null; + } + + if (isset($context['filters']['last']) && !isset($context['filters']['before'])) { + $context['count'] = (new DoctrineOrmPaginator($queryBuilder))->count(); + } + + return \array_slice($this->pagination->getPagination($operation, $context), 1); + } + + private function addLocalizationHints(QueryBuilder $queryBuilder, array $locales): Query + { + $query = $queryBuilder->getQuery(); + + $query->setHint( + Query::HINT_CUSTOM_OUTPUT_WALKER, + 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' + ); + + \array_reverse($locales); + foreach ($locales as $locale) { + $query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, $locale); + } + + $query->setHint(TranslatableListener::HINT_FALLBACK, 1); + + return $query; + } + + private function getContextLanguages(array $context): array + { + $tags = $context['request']->headers->get('Accept-Language', ''); + + return $this->localizationService->getLanguages($tags); + } +} diff --git a/src/Doctrine/PaginationExtensionTrait.php b/src/Doctrine/PaginationExtensionTrait.php new file mode 100644 index 0000000..5eb12e2 --- /dev/null +++ b/src/Doctrine/PaginationExtensionTrait.php @@ -0,0 +1,109 @@ +getPaginationFetchJoinCollection(); + + if (isset($context['operation_name']) && isset($fetchJoinCollection)) { + return $fetchJoinCollection; + } + + if (isset($context['graphql_operation_name']) && isset($fetchJoinCollection)) { + return $fetchJoinCollection; + } + + /* + * "Cannot count query which selects two FROM components, cannot make distinction" + * + * @see https://github.com/doctrine/orm/blob/v2.6.3/lib/Doctrine/ORM/Tools/Pagination/WhereInWalker.php#L81 + * @see https://github.com/doctrine/doctrine2/issues/2910 + */ + if (QueryChecker::hasRootEntityWithCompositeIdentifier($queryBuilder, $this->managerRegistry)) { + return false; + } + + if (QueryChecker::hasJoinedToManyAssociation($queryBuilder, $this->managerRegistry)) { + return true; + } + + // disable $fetchJoinCollection by default (performance) + return false; + } + + /** + * Determines whether the Doctrine ORM Paginator should use output walkers. + * + * Ported from api-platform/core source code + * + * @see https://github.com/api-platform/core/blob/a11c21335297b6026aa2b12fbe11a77e888481d7/src/Doctrine/Orm/Extension/PaginationExtension.php#L161 + */ + private function shouldDoctrinePaginatorUseOutputWalkers(QueryBuilder $queryBuilder, ?Operation $operation = null, array $context = []): bool + { + $useOutputWalkers = $operation?->getPaginationUseOutputWalkers(); + + if (isset($context['operation_name']) && isset($useOutputWalkers)) { + return $useOutputWalkers; + } + + if (isset($context['graphql_operation_name']) && isset($useOutputWalkers)) { + return $useOutputWalkers; + } + + /* + * "Cannot count query that uses a HAVING clause. Use the output walkers for pagination" + * + * @see https://github.com/doctrine/orm/blob/v2.6.3/lib/Doctrine/ORM/Tools/Pagination/CountWalker.php#L56 + */ + if (QueryChecker::hasHavingClause($queryBuilder)) { + return true; + } + + /* + * "Cannot count query which selects two FROM components, cannot make distinction" + * + * @see https://github.com/doctrine/orm/blob/v2.6.3/lib/Doctrine/ORM/Tools/Pagination/CountWalker.php#L64 + */ + if (QueryChecker::hasRootEntityWithCompositeIdentifier($queryBuilder, $this->managerRegistry)) { + return true; + } + + /* + * "Paginating an entity with foreign key as identifier only works when using the Output Walkers. Call Paginator#setUseOutputWalkers(true) before iterating the paginator." + * + * @see https://github.com/doctrine/orm/blob/v2.6.3/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php#L77 + */ + if (QueryChecker::hasRootEntityWithForeignKeyIdentifier($queryBuilder, $this->managerRegistry)) { + return true; + } + + /* + * "Cannot select distinct identifiers from query with LIMIT and ORDER BY on a column from a fetch joined to-many association. Use output walkers." + * + * @see https://github.com/doctrine/orm/blob/v2.6.3/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryWalker.php#L150 + */ + if (QueryChecker::hasMaxResults($queryBuilder) && QueryChecker::hasOrderByOnFetchJoinedToManyAssociation($queryBuilder, $this->managerRegistry)) { + return true; + } + + // Disable output walkers by default (performance) + return false; + } +} From 2735eec4cdf201e8740f101157d38bd57877a14c Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 14 Jan 2025 15:30:45 +0100 Subject: [PATCH 35/76] Set priority on localized content to take effect in correct order --- src/Doctrine/LocalizedContentExtension.php | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Doctrine/LocalizedContentExtension.php b/src/Doctrine/LocalizedContentExtension.php index 136e60b..fdeb80e 100644 --- a/src/Doctrine/LocalizedContentExtension.php +++ b/src/Doctrine/LocalizedContentExtension.php @@ -32,6 +32,17 @@ final class LocalizedContentExtension implements QueryResultCollectionExtensionI private Pagination $pagination, ) {} + /** + * Same priority as `api_platform.doctrine.orm.query_extension.pagination`. + * This ensures other filters can have precedence over localization. + * + * @see https://api-platform.com/docs/core/extensions/#custom-doctrine-orm-extension + */ + public static function getDefaultPriority(): int + { + return -64; + } + public function supportsResult(string $resourceClass, ?Operation $operation = null, array $context = []): bool { $reflectionClass = new \ReflectionClass($resourceClass); @@ -43,11 +54,11 @@ final class LocalizedContentExtension implements QueryResultCollectionExtensionI QueryBuilder $queryBuilder, ?string $resourceClass = null, ?Operation $operation = null, - array $context = [] + array $context = [], ): iterable { $query = $this->addLocalizationHints($queryBuilder, $this->getContextLanguages($context)); - if (1 === \count($queryBuilder->getAllAliases())) { + if (\count($queryBuilder->getAllAliases()) === 1) { $query->setHint(CountWalker::HINT_DISTINCT, false); } @@ -57,8 +68,7 @@ final class LocalizedContentExtension implements QueryResultCollectionExtensionI $isPartialEnabled = $this->pagination->isPartialEnabled($operation, $context); if ($isPartialEnabled) { - return new class($doctrineOrmPaginator) extends AbstractPaginator { - }; + return new class($doctrineOrmPaginator) extends AbstractPaginator {}; } return new Paginator($doctrineOrmPaginator); @@ -69,7 +79,7 @@ final class LocalizedContentExtension implements QueryResultCollectionExtensionI QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, - array $context = [] + array $context = [], ): void { if (null === $pagination = $this->getPagination($queryBuilder, $operation, $context)) { return; From 154f8a35daf7d662b2b1b193b9a83edcc489a060 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 14 Jan 2025 15:31:02 +0100 Subject: [PATCH 36/76] Update code on pagination trait --- src/Doctrine/PaginationExtensionTrait.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Doctrine/PaginationExtensionTrait.php b/src/Doctrine/PaginationExtensionTrait.php index 5eb12e2..703f897 100644 --- a/src/Doctrine/PaginationExtensionTrait.php +++ b/src/Doctrine/PaginationExtensionTrait.php @@ -10,15 +10,15 @@ trait PaginationExtensionTrait { /** * Determines the value of the $fetchJoinCollection argument passed to the Doctrine ORM Paginator. - * + * * Ported from api-platform/core source code - * + * * @see https://github.com/api-platform/core/blob/a11c21335297b6026aa2b12fbe11a77e888481d7/src/Doctrine/Orm/Extension/PaginationExtension.php#L128 */ private function shouldDoctrinePaginatorFetchJoinCollection( QueryBuilder $queryBuilder, ?Operation $operation = null, - array $context = [] + array $context = [], ): bool { $fetchJoinCollection = $operation?->getPaginationFetchJoinCollection(); @@ -50,9 +50,9 @@ trait PaginationExtensionTrait /** * Determines whether the Doctrine ORM Paginator should use output walkers. - * + * * Ported from api-platform/core source code - * + * * @see https://github.com/api-platform/core/blob/a11c21335297b6026aa2b12fbe11a77e888481d7/src/Doctrine/Orm/Extension/PaginationExtension.php#L161 */ private function shouldDoctrinePaginatorUseOutputWalkers(QueryBuilder $queryBuilder, ?Operation $operation = null, array $context = []): bool From 6c65e5d91b7a5b7a5251476caca9545144396a78 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 14 Jan 2025 15:33:28 +0100 Subject: [PATCH 37/76] Remove localized content provider --- config/services.yaml | 5 - src/State/ApiResourceStateProvider.php | 5 - src/State/LocalizedContentProvider.php | 206 ------------------------- 3 files changed, 216 deletions(-) delete mode 100644 src/State/LocalizedContentProvider.php diff --git a/config/services.yaml b/config/services.yaml index 978b78f..54bb91e 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -59,11 +59,6 @@ services: arguments: - '%env(APP_SECRET)%' - App\State\LocalizedContentProvider: - arguments: - $itemExtensions: !tagged api_platform.doctrine.orm.query_extension.item - $collectionExtensions: !tagged api_platform.doctrine.orm.query_extension.collection - App\Service\LocalizationService: arguments: - '%kernel.default_locale%' diff --git a/src/State/ApiResourceStateProvider.php b/src/State/ApiResourceStateProvider.php index 9c26242..9b41b71 100644 --- a/src/State/ApiResourceStateProvider.php +++ b/src/State/ApiResourceStateProvider.php @@ -19,15 +19,10 @@ class ApiResourceStateProvider implements ProviderInterface #[Autowire(service: ItemProvider::class)] private ProviderInterface $itemProvider, private AutoMapper $autoMapper, - private LocalizedContentProvider $localizedContentProvider, ) {} public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null { - if ($this->localizedContentProvider->supports($operation)) { - return $this->localizedContentProvider->provide($operation, $uriVariables, $context); - } - $resourceClass = $operation->getClass(); if ($operation instanceof CollectionOperationInterface) { diff --git a/src/State/LocalizedContentProvider.php b/src/State/LocalizedContentProvider.php deleted file mode 100644 index 880c689..0000000 --- a/src/State/LocalizedContentProvider.php +++ /dev/null @@ -1,206 +0,0 @@ -getClass(); - $entityClass = $this->getEntityClass($operation); - - $manager = $this->managerRegistry->getManagerForClass($entityClass); - - if ($manager === null) { - throw new \RuntimeException(); - } - - $repository = $manager->getRepository($entityClass); - - if (!$repository instanceof EntityRepository) { - throw new \RuntimeException(); - } - - $queryBuilder = $repository->createQueryBuilder('o'); - $queryNameGenerator = new QueryNameGenerator(); - - if ($operation instanceof CollectionOperationInterface) { - $collection = $this->provideCollection($queryBuilder, $queryNameGenerator, $entityClass, $operation, $context); - - $resources = []; - foreach ($collection as $item) { - $resources[] = $this->autoMapper->map($item, $resourceClass); - } - - return new TraversablePaginator( - new \ArrayIterator($resources), - $this->pagination->getPage($context), - $this->pagination->getLimit($operation, $context), - \count($collection) - ); - } - - $item = $this->provideItem($queryBuilder, $queryNameGenerator, $entityClass, $operation, $context); - - if (!$item) { - return null; - } - - return $this->autoMapper->map($item, $resourceClass); - } - - /** - * Determine wether an API operation is localizable or not. - * - * @param Operation $operation The operation as given to the providers - * - * @return bool `true` if the underlying entity is localizable - */ - public function supports(Operation $operation): bool - { - $reflectionClass = new \ReflectionClass($this->getEntityClass($operation)); - - return $reflectionClass->implementsInterface(LocalizedContentInterface::class); - } - - private function getEntityClass(Operation $operation): string - { - /** @var Options */ - $options = $operation->getStateOptions(); - - return $options->getEntityClass(); - } - - /** - * Add a hint for each locale to the query. - * - * @param Query $query The query where the translation hints should be added - * @param string[] $locales A list of the locales to be hinted - * - * @return Query The input query with added hints - * - * @see https://github.com/doctrine-extensions/DoctrineExtensions/blob/main/doc/translatable.md#using-orm-query-hint - */ - private function addTranslatableQueryHints(Query $query, array $locales): Query - { - $query->setHint( - Query::HINT_CUSTOM_OUTPUT_WALKER, - 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' - ); - - $locales = \array_reverse($locales); - foreach ($locales as $locale) { - $query->setHint( - TranslatableListener::HINT_TRANSLATABLE_LOCALE, - $locale - ); - } - - $query->setHint(TranslatableListener::HINT_FALLBACK, 0); - $query->setHint(TranslatableListener::HINT_INNER_JOIN, true); - - return $query; - } - - /** - * @param array|array{request: unset|\Symfony\Component\HttpFoundation\Request, resource_class: unset|string} $context - */ - private function provideCollection( - QueryBuilder $queryBuilder, - QueryNameGenerator $queryNameGenerator, - string $entityClass, - Operation $operation, - array $context = [], - ) { - $queryBuilder - ->setFirstResult($this->pagination->getOffset($operation, $context)) - ->setMaxResults($this->pagination->getLimit($operation, $context)); - - foreach ($this->collectionExtensions as $extension) { - $extension->applyToCollection( - $queryBuilder, - $queryNameGenerator, - $entityClass, - $operation, - $context - ); - } - - $languages = $context['request']->headers->get('Accept-Language', ''); - - $query = $this->addTranslatableQueryHints( - $queryBuilder->getQuery()->useQueryCache(true)->enableResultCache(), - $this->localizationService->getLanguages($languages) - ); - - return $query->getResult(); - } - - /** - * @param array|array{request: unset|\Symfony\Component\HttpFoundation\Request, resource_class: unset|string} $context - */ - private function provideItem( - QueryBuilder $queryBuilder, - QueryNameGenerator $queryNameGenerator, - string $entityClass, - Operation $operation, - array $context = [], - ) { - $rootAlias = $queryBuilder->getRootAliases()[0]; - $queryBuilder->where($queryBuilder->expr()->eq(\sprintf('%s.id', $rootAlias), $context['uri_variables']['id'])); - - foreach ($this->itemExtensions as $extension) { - $extension->applyToItem( - $queryBuilder, - $queryNameGenerator, - $entityClass, - $context['uri_variables'], - $operation, - $context - ); - } - - $languages = $context['request']->headers->get('Accept-Language', ''); - - $query = $this->addTranslatableQueryHints( - $queryBuilder->getQuery()->useQueryCache(true)->enableResultCache(), - $this->localizationService->getLanguages($languages) - ); - - return $query->getOneOrNullResult(); - } -} From c6e8ccf345685b5605d70df152ad432715e9c2ae Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 14 Jan 2025 15:44:15 +0100 Subject: [PATCH 38/76] Move generic localization extension code to trait --- src/Doctrine/LocalizedContentTrait.php | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/Doctrine/LocalizedContentTrait.php diff --git a/src/Doctrine/LocalizedContentTrait.php b/src/Doctrine/LocalizedContentTrait.php new file mode 100644 index 0000000..921edc6 --- /dev/null +++ b/src/Doctrine/LocalizedContentTrait.php @@ -0,0 +1,36 @@ +getQuery(); + + $query->setHint( + Query::HINT_CUSTOM_OUTPUT_WALKER, + 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' + ); + + \array_reverse($locales); + foreach ($locales as $locale) { + $query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, $locale); + } + + $query->setHint(TranslatableListener::HINT_FALLBACK, 1); + + return $query; + } + + private function getContextLanguages(array $context): array + { + $tags = $context['request']->headers->get('Accept-Language', ''); + + return $this->localizationService->getLanguages($tags); + } +} From 040cdf1f34cad96883db050aae6278358d53ffb4 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 14 Jan 2025 15:55:27 +0100 Subject: [PATCH 39/76] Rename localized content extension to collection --- ...n.php => LocalizedCollectionExtension.php} | 31 ++----------------- 1 file changed, 2 insertions(+), 29 deletions(-) rename src/Doctrine/{LocalizedContentExtension.php => LocalizedCollectionExtension.php} (80%) diff --git a/src/Doctrine/LocalizedContentExtension.php b/src/Doctrine/LocalizedCollectionExtension.php similarity index 80% rename from src/Doctrine/LocalizedContentExtension.php rename to src/Doctrine/LocalizedCollectionExtension.php index fdeb80e..82608b8 100644 --- a/src/Doctrine/LocalizedContentExtension.php +++ b/src/Doctrine/LocalizedCollectionExtension.php @@ -10,20 +10,19 @@ use ApiPlatform\Metadata\Operation; use ApiPlatform\State\Pagination\Pagination; use App\Entity\Interface\LocalizedContentInterface; use App\Service\LocalizationService; -use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Tools\Pagination\CountWalker; use Doctrine\ORM\Tools\Pagination\Paginator as DoctrineOrmPaginator; use Doctrine\Persistence\ManagerRegistry; -use Gedmo\Translatable\TranslatableListener; /** * Adds localization hints to translatable entity queries. * * @see https://github.com/doctrine-extensions/DoctrineExtensions/blob/main/doc/translatable.md#using-orm-query-hint */ -final class LocalizedContentExtension implements QueryResultCollectionExtensionInterface +final class LocalizedCollectionExtension implements QueryResultCollectionExtensionInterface { + use LocalizedContentTrait; use PaginationExtensionTrait; public function __construct( @@ -109,30 +108,4 @@ final class LocalizedContentExtension implements QueryResultCollectionExtensionI return \array_slice($this->pagination->getPagination($operation, $context), 1); } - - private function addLocalizationHints(QueryBuilder $queryBuilder, array $locales): Query - { - $query = $queryBuilder->getQuery(); - - $query->setHint( - Query::HINT_CUSTOM_OUTPUT_WALKER, - 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' - ); - - \array_reverse($locales); - foreach ($locales as $locale) { - $query->setHint(TranslatableListener::HINT_TRANSLATABLE_LOCALE, $locale); - } - - $query->setHint(TranslatableListener::HINT_FALLBACK, 1); - - return $query; - } - - private function getContextLanguages(array $context): array - { - $tags = $context['request']->headers->get('Accept-Language', ''); - - return $this->localizationService->getLanguages($tags); - } } From 5f4cac0807b3c72c473cdec330c3a15738c10068 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 14 Jan 2025 16:08:57 +0100 Subject: [PATCH 40/76] Inject localization service in localized trait via required attribute --- src/Doctrine/LocalizedContentTrait.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Doctrine/LocalizedContentTrait.php b/src/Doctrine/LocalizedContentTrait.php index 921edc6..6608301 100644 --- a/src/Doctrine/LocalizedContentTrait.php +++ b/src/Doctrine/LocalizedContentTrait.php @@ -2,12 +2,22 @@ namespace App\Doctrine; +use App\Service\LocalizationService; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; use Gedmo\Translatable\TranslatableListener; +use Symfony\Contracts\Service\Attribute\Required; trait LocalizedContentTrait { + protected LocalizationService $localizationService; + + #[Required] + public function setLocalizationService(LocalizationService $localizationService) + { + $this->localizationService = $localizationService; + } + private function addLocalizationHints(QueryBuilder $queryBuilder, array $locales): Query { $query = $queryBuilder->getQuery(); From f59f96f78fc1f924a77612dabcafdcd4b47769e9 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 14 Jan 2025 16:09:25 +0100 Subject: [PATCH 41/76] Inject pagination dependencies in trait via required attribute --- src/Doctrine/LocalizedCollectionExtension.php | 9 --------- src/Doctrine/PaginationExtensionTrait.php | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Doctrine/LocalizedCollectionExtension.php b/src/Doctrine/LocalizedCollectionExtension.php index 82608b8..2eab85e 100644 --- a/src/Doctrine/LocalizedCollectionExtension.php +++ b/src/Doctrine/LocalizedCollectionExtension.php @@ -7,13 +7,10 @@ use ApiPlatform\Doctrine\Orm\Extension\QueryResultCollectionExtensionInterface; use ApiPlatform\Doctrine\Orm\Paginator; use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Metadata\Operation; -use ApiPlatform\State\Pagination\Pagination; use App\Entity\Interface\LocalizedContentInterface; -use App\Service\LocalizationService; use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Tools\Pagination\CountWalker; use Doctrine\ORM\Tools\Pagination\Paginator as DoctrineOrmPaginator; -use Doctrine\Persistence\ManagerRegistry; /** * Adds localization hints to translatable entity queries. @@ -25,12 +22,6 @@ final class LocalizedCollectionExtension implements QueryResultCollectionExtensi use LocalizedContentTrait; use PaginationExtensionTrait; - public function __construct( - private LocalizationService $localizationService, - private ManagerRegistry $managerRegistry, - private Pagination $pagination, - ) {} - /** * Same priority as `api_platform.doctrine.orm.query_extension.pagination`. * This ensures other filters can have precedence over localization. diff --git a/src/Doctrine/PaginationExtensionTrait.php b/src/Doctrine/PaginationExtensionTrait.php index 703f897..4adee8b 100644 --- a/src/Doctrine/PaginationExtensionTrait.php +++ b/src/Doctrine/PaginationExtensionTrait.php @@ -4,10 +4,29 @@ namespace App\Doctrine; use ApiPlatform\Doctrine\Orm\Util\QueryChecker; use ApiPlatform\Metadata\Operation; +use ApiPlatform\State\Pagination\Pagination; use Doctrine\ORM\QueryBuilder; +use Doctrine\Persistence\ManagerRegistry; +use Symfony\Contracts\Service\Attribute\Required; trait PaginationExtensionTrait { + protected Pagination $pagination; + + protected ManagerRegistry $managerRegistry; + + #[Required] + public function setManagerRegistry(ManagerRegistry $managerRegistry) + { + $this->managerRegistry = $managerRegistry; + } + + #[Required] + public function setPagination(Pagination $pagination) + { + $this->pagination = $pagination; + } + /** * Determines the value of the $fetchJoinCollection argument passed to the Doctrine ORM Paginator. * From 7abaee0e975e9259f44017ab061d7295e9e32fc8 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 14 Jan 2025 16:09:59 +0100 Subject: [PATCH 42/76] Add localized item doctrine extension --- src/Doctrine/LocalizedItemExtension.php | 57 +++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/Doctrine/LocalizedItemExtension.php diff --git a/src/Doctrine/LocalizedItemExtension.php b/src/Doctrine/LocalizedItemExtension.php new file mode 100644 index 0000000..9604b1d --- /dev/null +++ b/src/Doctrine/LocalizedItemExtension.php @@ -0,0 +1,57 @@ +implementsInterface(LocalizedContentInterface::class); + } + + public function getResult( + QueryBuilder $queryBuilder, + ?string $resourceClass = null, + ?Operation $operation = null, + array $context = [] + ): ?object { + $query = $this->addLocalizationHints($queryBuilder, $this->getContextLanguages($context)); + + return $query->getOneOrNullResult(); + } + + public function applyToItem( + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + string $resourceClass, + array $identifiers, + ?Operation $operation = null, + array $context = [] + ): void {} +} From c661843b253ea0591e902038fa9f75e3d507ab89 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Tue, 14 Jan 2025 16:11:52 +0100 Subject: [PATCH 43/76] Move support result method to localized trait --- src/Doctrine/LocalizedCollectionExtension.php | 8 -------- src/Doctrine/LocalizedContentTrait.php | 9 +++++++++ src/Doctrine/LocalizedItemExtension.php | 12 ++---------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/Doctrine/LocalizedCollectionExtension.php b/src/Doctrine/LocalizedCollectionExtension.php index 2eab85e..99923f5 100644 --- a/src/Doctrine/LocalizedCollectionExtension.php +++ b/src/Doctrine/LocalizedCollectionExtension.php @@ -7,7 +7,6 @@ use ApiPlatform\Doctrine\Orm\Extension\QueryResultCollectionExtensionInterface; use ApiPlatform\Doctrine\Orm\Paginator; use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Metadata\Operation; -use App\Entity\Interface\LocalizedContentInterface; use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Tools\Pagination\CountWalker; use Doctrine\ORM\Tools\Pagination\Paginator as DoctrineOrmPaginator; @@ -33,13 +32,6 @@ final class LocalizedCollectionExtension implements QueryResultCollectionExtensi return -64; } - public function supportsResult(string $resourceClass, ?Operation $operation = null, array $context = []): bool - { - $reflectionClass = new \ReflectionClass($resourceClass); - - return $reflectionClass->implementsInterface(LocalizedContentInterface::class); - } - public function getResult( QueryBuilder $queryBuilder, ?string $resourceClass = null, diff --git a/src/Doctrine/LocalizedContentTrait.php b/src/Doctrine/LocalizedContentTrait.php index 6608301..31ec57e 100644 --- a/src/Doctrine/LocalizedContentTrait.php +++ b/src/Doctrine/LocalizedContentTrait.php @@ -2,6 +2,8 @@ namespace App\Doctrine; +use ApiPlatform\Metadata\Operation; +use App\Entity\Interface\LocalizedContentInterface; use App\Service\LocalizationService; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; @@ -18,6 +20,13 @@ trait LocalizedContentTrait $this->localizationService = $localizationService; } + public function supportsResult(string $resourceClass, ?Operation $operation = null, array $context = []): bool + { + $reflectionClass = new \ReflectionClass($resourceClass); + + return $reflectionClass->implementsInterface(LocalizedContentInterface::class); + } + private function addLocalizationHints(QueryBuilder $queryBuilder, array $locales): Query { $query = $queryBuilder->getQuery(); diff --git a/src/Doctrine/LocalizedItemExtension.php b/src/Doctrine/LocalizedItemExtension.php index 9604b1d..fd1cf45 100644 --- a/src/Doctrine/LocalizedItemExtension.php +++ b/src/Doctrine/LocalizedItemExtension.php @@ -5,7 +5,6 @@ namespace App\Doctrine; use ApiPlatform\Doctrine\Orm\Extension\QueryResultItemExtensionInterface; use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Metadata\Operation; -use App\Entity\Interface\LocalizedContentInterface; use Doctrine\ORM\QueryBuilder; /** @@ -28,18 +27,11 @@ final class LocalizedItemExtension implements QueryResultItemExtensionInterface return -64; } - public function supportsResult(string $resourceClass, ?Operation $operation = null, array $context = []): bool - { - $reflectionClass = new \ReflectionClass($resourceClass); - - return $reflectionClass->implementsInterface(LocalizedContentInterface::class); - } - public function getResult( QueryBuilder $queryBuilder, ?string $resourceClass = null, ?Operation $operation = null, - array $context = [] + array $context = [], ): ?object { $query = $this->addLocalizationHints($queryBuilder, $this->getContextLanguages($context)); @@ -52,6 +44,6 @@ final class LocalizedItemExtension implements QueryResultItemExtensionInterface string $resourceClass, array $identifiers, ?Operation $operation = null, - array $context = [] + array $context = [], ): void {} } From d539259b114783db7ef99ab4404ec517fb831ee1 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 15 Jan 2025 12:51:39 +0100 Subject: [PATCH 44/76] Update localization description to add removal specs --- src/OpenApi/OpenApiDescription.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/OpenApi/OpenApiDescription.md b/src/OpenApi/OpenApiDescription.md index f7ff850..8f11645 100644 --- a/src/OpenApi/OpenApiDescription.md +++ b/src/OpenApi/OpenApiDescription.md @@ -33,4 +33,8 @@ The v4 API accepts localization of content. Resources such as Projects can have Retrieval of content in different locales is performed via standard HTTP [content negotiation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation). When the request supplies an `Accept-Language` header, the API will retrieve localized versions of the content where available, falling back to the default locale of the API instance, and finally to the first available localization of the content regardless of the request preferences or the API defaults if it cannot find suitable localizations. -Submission of localized content is performed over standard HTTP content submission with the addition of a `Content-Language` header to a POST, PUT or PATCH request. Localizations are assumed to be one per language globally. Contained tags will be matched to an [ISO 639](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) two-letter code and only the first tag will be used to determine the submitted localization, e.g: a value of "ca_ES, es_ES", for a text primarily in Catalan (ca_ES) and bits in Spanish (es_ES) will be converted to "ca", ignoring the Spanish language tag and the "ES" subtag in "ca_ES". +Submission of localized content is performed over standard REST content submission with the addition of a `Content-Language` header to a POST, PUT or PATCH request. Only the first tag will be used to determine the submitted localization. + +Removal of localized content is performed over standard REST content deletion with the addition of a `Content-Language` header to a DELETE request. A delete request for localized content will act partially and remove only the requested localizations, not the entire resource. To remove the resource you can send a non-localized request omitting the `Content-Language` header. Unlike on submission v4 will process all language tags included in the header and remove every matching localization. + +Localizations are assumed to be one per language globally. Language tags will be parsed to match to an [ISO 639](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) two-letter languade code, e.g: a value of "en_US" will be converted to "en", ignoring the "US" subtag. From 481950093fc3da1015f4ba3ff8dbbf4faa5ae2fc Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 15 Jan 2025 13:18:50 +0100 Subject: [PATCH 45/76] Update LocalizedContentInterface to allow removal of locales --- src/Entity/Interface/LocalizedContentInterface.php | 7 +++++++ src/Entity/Trait/LocalizedContent.php | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/Entity/Interface/LocalizedContentInterface.php b/src/Entity/Interface/LocalizedContentInterface.php index 4ae11c3..0dc6338 100644 --- a/src/Entity/Interface/LocalizedContentInterface.php +++ b/src/Entity/Interface/LocalizedContentInterface.php @@ -13,6 +13,8 @@ use Gedmo\Translatable\Translatable; */ interface LocalizedContentInterface extends Translatable { + public function getId(): ?int; + /** * Set the locale of the working content for translations. */ @@ -28,6 +30,11 @@ interface LocalizedContentInterface extends Translatable */ public function addLocale(string $locale): static; + /** + * Remove from the list of available translation locales. + */ + public function removeLocale(string $locale): static; + /** * Set the list of available translation locales. */ diff --git a/src/Entity/Trait/LocalizedContent.php b/src/Entity/Trait/LocalizedContent.php index e2c9628..4a5d7dd 100644 --- a/src/Entity/Trait/LocalizedContent.php +++ b/src/Entity/Trait/LocalizedContent.php @@ -32,6 +32,18 @@ trait LocalizedContent return $this; } + public function removeLocale(string $locale): static + { + $needle = $locale; + + $this->locales = [...\array_filter($this->locales, function (string $locale) use ($needle) { + return $locale !== $needle; + })]; + + return $this; + } + + public function setLocales(array $locales): static { $this->locales = $locales; From 172e5f36f10e2219538196f86a7b047e2282edb6 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 15 Jan 2025 13:19:29 +0100 Subject: [PATCH 46/76] Fix bug on project deletion --- src/State/Project/ProjectStateProcessor.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/State/Project/ProjectStateProcessor.php b/src/State/Project/ProjectStateProcessor.php index 673686c..8055415 100644 --- a/src/State/Project/ProjectStateProcessor.php +++ b/src/State/Project/ProjectStateProcessor.php @@ -41,6 +41,10 @@ class ProjectStateProcessor implements ProcessorInterface $project = $this->entityStateProcessor->process($project, $operation, $uriVariables, $context); + if ($project === null) { + return null; + } + return $this->autoMapper->map($project, $data); } } From dece03dc3f933e4b83c755bacceeb0ea0d24b1ec Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 15 Jan 2025 13:19:58 +0100 Subject: [PATCH 47/76] Process localized content as described in the api spec --- src/State/EntityStateProcessor.php | 85 +++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 7 deletions(-) diff --git a/src/State/EntityStateProcessor.php b/src/State/EntityStateProcessor.php index 6c9c564..ef17608 100644 --- a/src/State/EntityStateProcessor.php +++ b/src/State/EntityStateProcessor.php @@ -9,8 +9,9 @@ use ApiPlatform\Metadata\Operation; use ApiPlatform\State\ProcessorInterface; use App\Entity\Interface\LocalizedContentInterface; use App\Service\LocalizationService; +use Doctrine\ORM\EntityManagerInterface; +use Gedmo\Translatable\Entity\Translation; use Symfony\Component\DependencyInjection\Attribute\Autowire; -use Symfony\Component\HttpFoundation\Request; class EntityStateProcessor implements ProcessorInterface { @@ -20,6 +21,7 @@ class EntityStateProcessor implements ProcessorInterface #[Autowire(service: PersistProcessor::class)] private ProcessorInterface $persistProcessor, private LocalizationService $localizationService, + private EntityManagerInterface $entityManager, ) {} /** @@ -28,12 +30,7 @@ class EntityStateProcessor implements ProcessorInterface public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []) { if ($data instanceof LocalizedContentInterface) { - /** @var Request */ - $request = $context['request']; - - $data->setTranslatableLocale($this->localizationService->getLanguage( - $request->headers->get('Content-Language'), - )); + return $this->processLocalizedContent($data, $operation, $uriVariables, $context); } if ($operation instanceof DeleteOperationInterface) { @@ -42,4 +39,78 @@ class EntityStateProcessor implements ProcessorInterface return $this->persistProcessor->process($data, $operation, $uriVariables, $context); } + + private function processLocalizedContent( + LocalizedContentInterface $data, + Operation $operation, + array $uriVariables = [], + array $context = [], + ): mixed { + $languages = $this->getContextLanguages($context); + + if ($operation instanceof DeleteOperationInterface) { + if ($languages === null) { + return $this->deleteProcessor->process($data, $operation, $uriVariables, $context); + } + + return $this->deleteLocalizedContent($data, $operation, $uriVariables, $context, $languages); + } + + $language = $languages ? $languages[0] : $this->localizationService->getDefaultLanguage(); + + $data->setTranslatableLocale($language); + + return $this->persistProcessor->process($data, $operation, $uriVariables, $context); + } + + private function getContextLanguages(array $context): ?array + { + $tags = $context['request']->headers->get('Content-Language', ''); + + if (empty($tags)) { + return null; + } + + return $this->localizationService->getLanguages($tags); + } + + private function deleteLocalizedContent( + LocalizedContentInterface $data, + Operation $operation, + array $uriVariables = [], + array $context = [], + array $languages = [] + ) { + $translationRepository = $this->entityManager->getRepository(Translation::class); + + if (!\array_diff($data->getLocales(), $languages)) { + throw new \Exception("Cannot leave empty resource. Must have at least one available localization."); + } + + $nonLocalizedLanguages = \array_diff($languages, $data->getLocales()); + if (!empty($nonLocalizedLanguages)) { + throw new \Exception(\sprintf( + "Could not find requested localizations '%s' of the resource.", + \join(', ', $nonLocalizedLanguages) + )); + } + + foreach ($languages as $language) { + $translations = $translationRepository->findBy([ + 'locale' => $language, + 'objectClass' => $data::class, + 'foreignKey' => $data->getId() + ]); + + foreach ($translations as $translation) { + $this->entityManager->remove($translation); + } + + $data->removeLocale($language); + } + + $this->entityManager->flush(); + + return $this->persistProcessor->process($data, $operation, $uriVariables, $context); + } } From 825c319e4048aa5a2cf18288d2310df119904edf Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 15 Jan 2025 13:22:12 +0100 Subject: [PATCH 48/76] Rename LocalizedContentTrait to LocalizedExtensionTrait to avoid confusion with LocalizedContent* entity focused classes --- src/Doctrine/LocalizedCollectionExtension.php | 2 +- .../{LocalizedContentTrait.php => LocalizedExtensionTrait.php} | 2 +- src/Doctrine/LocalizedItemExtension.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/Doctrine/{LocalizedContentTrait.php => LocalizedExtensionTrait.php} (98%) diff --git a/src/Doctrine/LocalizedCollectionExtension.php b/src/Doctrine/LocalizedCollectionExtension.php index 99923f5..8755ef9 100644 --- a/src/Doctrine/LocalizedCollectionExtension.php +++ b/src/Doctrine/LocalizedCollectionExtension.php @@ -18,7 +18,7 @@ use Doctrine\ORM\Tools\Pagination\Paginator as DoctrineOrmPaginator; */ final class LocalizedCollectionExtension implements QueryResultCollectionExtensionInterface { - use LocalizedContentTrait; + use LocalizedExtensionTrait; use PaginationExtensionTrait; /** diff --git a/src/Doctrine/LocalizedContentTrait.php b/src/Doctrine/LocalizedExtensionTrait.php similarity index 98% rename from src/Doctrine/LocalizedContentTrait.php rename to src/Doctrine/LocalizedExtensionTrait.php index 31ec57e..32f02e6 100644 --- a/src/Doctrine/LocalizedContentTrait.php +++ b/src/Doctrine/LocalizedExtensionTrait.php @@ -10,7 +10,7 @@ use Doctrine\ORM\QueryBuilder; use Gedmo\Translatable\TranslatableListener; use Symfony\Contracts\Service\Attribute\Required; -trait LocalizedContentTrait +trait LocalizedExtensionTrait { protected LocalizationService $localizationService; diff --git a/src/Doctrine/LocalizedItemExtension.php b/src/Doctrine/LocalizedItemExtension.php index fd1cf45..ed83877 100644 --- a/src/Doctrine/LocalizedItemExtension.php +++ b/src/Doctrine/LocalizedItemExtension.php @@ -14,7 +14,7 @@ use Doctrine\ORM\QueryBuilder; */ final class LocalizedItemExtension implements QueryResultItemExtensionInterface { - use LocalizedContentTrait; + use LocalizedExtensionTrait; /** * Same priority as `api_platform.doctrine.orm.query_extension.pagination`. From e0ba10b1bab529a321197d763622b6250782989e Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 15 Jan 2025 13:24:08 +0100 Subject: [PATCH 49/76] Code style fixes --- src/Entity/Trait/LocalizedContent.php | 1 - src/State/EntityStateProcessor.php | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Entity/Trait/LocalizedContent.php b/src/Entity/Trait/LocalizedContent.php index 4a5d7dd..0ce1bb8 100644 --- a/src/Entity/Trait/LocalizedContent.php +++ b/src/Entity/Trait/LocalizedContent.php @@ -43,7 +43,6 @@ trait LocalizedContent return $this; } - public function setLocales(array $locales): static { $this->locales = $locales; diff --git a/src/State/EntityStateProcessor.php b/src/State/EntityStateProcessor.php index ef17608..98ade6a 100644 --- a/src/State/EntityStateProcessor.php +++ b/src/State/EntityStateProcessor.php @@ -79,12 +79,12 @@ class EntityStateProcessor implements ProcessorInterface Operation $operation, array $uriVariables = [], array $context = [], - array $languages = [] + array $languages = [], ) { $translationRepository = $this->entityManager->getRepository(Translation::class); if (!\array_diff($data->getLocales(), $languages)) { - throw new \Exception("Cannot leave empty resource. Must have at least one available localization."); + throw new \Exception('Cannot leave empty resource. Must have at least one available localization.'); } $nonLocalizedLanguages = \array_diff($languages, $data->getLocales()); @@ -99,7 +99,7 @@ class EntityStateProcessor implements ProcessorInterface $translations = $translationRepository->findBy([ 'locale' => $language, 'objectClass' => $data::class, - 'foreignKey' => $data->getId() + 'foreignKey' => $data->getId(), ]); foreach ($translations as $translation) { From 294c4da621326ec87bb5c6e20717d95a845b468b Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 15 Jan 2025 16:33:05 +0100 Subject: [PATCH 50/76] Specify checkout gateway mapping as name --- src/ApiResource/Gateway/CheckoutApiResource.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ApiResource/Gateway/CheckoutApiResource.php b/src/ApiResource/Gateway/CheckoutApiResource.php index a1bc838..2ee2cfe 100644 --- a/src/ApiResource/Gateway/CheckoutApiResource.php +++ b/src/ApiResource/Gateway/CheckoutApiResource.php @@ -12,6 +12,7 @@ use App\Gateway\Tracking; use App\State\ApiResourceStateProvider; use App\State\Gateway\CheckoutStateProcessor; use AutoMapper\Attribute\MapFrom; +use AutoMapper\Attribute\MapTo; use Symfony\Component\Validator\Constraints as Assert; /** @@ -35,6 +36,7 @@ class CheckoutApiResource * The desired Gateway to checkout with. */ #[Assert\NotBlank()] + #[MapTo(property: 'gatewayName', transformer: 'source.gateway.name')] public GatewayApiResource $gateway; /** From 44be1e05fb0be1a2ccfcc37c4c9b9cc2ca832ca9 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 15 Jan 2025 16:33:26 +0100 Subject: [PATCH 51/76] Remove unnecessary accounting resource owner setting --- src/State/Accounting/AccountingStateProvider.php | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/State/Accounting/AccountingStateProvider.php b/src/State/Accounting/AccountingStateProvider.php index 3ef5d91..4c4e25a 100644 --- a/src/State/Accounting/AccountingStateProvider.php +++ b/src/State/Accounting/AccountingStateProvider.php @@ -65,21 +65,6 @@ class AccountingStateProvider implements ProviderInterface $resource = $this->autoMapper->map($accounting, AccountingApiResource::class); $resource->balance = $this->accountingService->calcBalance($accounting); - $owner = $accounting->getOwner(); - - switch ($owner::class) { - case User::class: - $resourceClass = UserApiResource::class; - break; - case Project::class: - $resourceClass = ProjectApiResource::class; - break; - case Tipjar::class: - $resourceClass = Tipjar::class; - } - - $resource->owner = $this->autoMapper->map($owner, $resourceClass); - return $resource; } } From 59883a7a42c6fb704868ad44c887af1c50ab7cb7 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Wed, 15 Jan 2025 16:34:37 +0100 Subject: [PATCH 52/76] Fix cascade persistence on charge and checkout --- src/Entity/Gateway/Charge.php | 2 +- src/Entity/Gateway/Checkout.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Entity/Gateway/Charge.php b/src/Entity/Gateway/Charge.php index c7d6165..f7c348e 100644 --- a/src/Entity/Gateway/Charge.php +++ b/src/Entity/Gateway/Charge.php @@ -51,7 +51,7 @@ class Charge * The Accounting receiving the consequent Transaction for this GatewayCharge. */ #[Assert\NotBlank()] - #[ORM\ManyToOne] + #[ORM\ManyToOne(cascade: ['persist'])] #[ORM\JoinColumn(nullable: false)] private ?Accounting $target = null; diff --git a/src/Entity/Gateway/Checkout.php b/src/Entity/Gateway/Checkout.php index 8394c43..bebb762 100644 --- a/src/Entity/Gateway/Checkout.php +++ b/src/Entity/Gateway/Checkout.php @@ -41,7 +41,7 @@ class Checkout * The Accounting that will issue the Transactions of the GatewayCharges after a successful checkout. */ #[Assert\NotBlank()] - #[ORM\ManyToOne] + #[ORM\ManyToOne(cascade: ['persist'])] #[ORM\JoinColumn(nullable: false)] private ?Accounting $origin = null; From 2b6b5c5cbcd4b43d52c18a8794cb7dfbca2482b4 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 16 Jan 2025 10:59:22 +0100 Subject: [PATCH 53/76] Throw exception when non user checking out with stripe --- src/Gateway/Stripe/StripeGateway.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Gateway/Stripe/StripeGateway.php b/src/Gateway/Stripe/StripeGateway.php index dc69356..fe86b00 100644 --- a/src/Gateway/Stripe/StripeGateway.php +++ b/src/Gateway/Stripe/StripeGateway.php @@ -4,7 +4,7 @@ namespace App\Gateway\Stripe; use ApiPlatform\Api\IriConverterInterface; use App\Entity\Gateway\Checkout; -use App\Entity\User; +use App\Entity\User\User; use App\Gateway\ChargeType; use App\Gateway\CheckoutStatus; use App\Gateway\GatewayInterface; @@ -136,7 +136,10 @@ class StripeGateway implements GatewayInterface { $owner = $checkout->getOrigin()->getOwner(); if (!$owner instanceof User) { - return ''; + throw new \Exception(\sprintf( + "Checkout with Stripe must be performed by an User, instance of '%s' supplied", + $owner::class + )); } return $owner->getEmail(); From d6f932e48bd043e44c1bb3aed30989d3e74be384 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 16 Jan 2025 11:10:01 +0100 Subject: [PATCH 54/76] Inject property transformers on decorated automapper --- config/services.yaml | 3 +++ src/Mapping/AutoMapper.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/config/services.yaml b/config/services.yaml index 8a6bc90..1ef66fb 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -20,6 +20,8 @@ services: tags: ['app.lib.economy.currency.exchange'] AutoMapper\Provider\ProviderInterface: tags: ['app.mapping.map_provider'] + AutoMapper\Transformer\PropertyTransformer\PropertyTransformerInterface: + tags: ['app.mapping.map_transformer'] # makes classes in src/ available to be used as services # this creates a service per class whose id is the fully-qualified class name @@ -71,6 +73,7 @@ services: arguments: - '%kernel.cache_dir%' - !tagged 'app.mapping.map_provider' + - !tagged 'app.mapping.map_transformer' # add more service definitions when explicit configuration is needed # please note that last definitions always *replace* previous ones diff --git a/src/Mapping/AutoMapper.php b/src/Mapping/AutoMapper.php index c9c10fc..1e20c33 100644 --- a/src/Mapping/AutoMapper.php +++ b/src/Mapping/AutoMapper.php @@ -18,10 +18,12 @@ class AutoMapper implements AutoMapperInterface public function __construct( ?string $cacheDirectory = null, iterable $mapProviders = [], + iterable $mapTransformers = [], ) { $this->innerMapper = InnerMapper::create( cacheDirectory: \sprintf('%s%s%s', $cacheDirectory, \DIRECTORY_SEPARATOR, self::CACHE_DIR), providers: $mapProviders, + propertyTransformers: $mapTransformers, ); } From 880221e11a3e14ee270cfa5efe1fde0e25ed5821 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 16 Jan 2025 11:10:23 +0100 Subject: [PATCH 55/76] Use transformer to map entity gateway names to resource gateways --- .../Gateway/CheckoutApiResource.php | 2 ++ .../Transformer/GatewayNameMapTransformer.php | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 src/Mapping/Transformer/GatewayNameMapTransformer.php diff --git a/src/ApiResource/Gateway/CheckoutApiResource.php b/src/ApiResource/Gateway/CheckoutApiResource.php index 2ee2cfe..1ad6b23 100644 --- a/src/ApiResource/Gateway/CheckoutApiResource.php +++ b/src/ApiResource/Gateway/CheckoutApiResource.php @@ -9,6 +9,7 @@ use App\Entity\Gateway\Checkout; use App\Gateway\CheckoutStatus; use App\Gateway\Link; use App\Gateway\Tracking; +use App\Mapping\Transformer\GatewayNameMapTransformer; use App\State\ApiResourceStateProvider; use App\State\Gateway\CheckoutStateProcessor; use AutoMapper\Attribute\MapFrom; @@ -36,6 +37,7 @@ class CheckoutApiResource * The desired Gateway to checkout with. */ #[Assert\NotBlank()] + #[MapFrom(property: 'gatewayName', transformer: GatewayNameMapTransformer::class)] #[MapTo(property: 'gatewayName', transformer: 'source.gateway.name')] public GatewayApiResource $gateway; diff --git a/src/Mapping/Transformer/GatewayNameMapTransformer.php b/src/Mapping/Transformer/GatewayNameMapTransformer.php new file mode 100644 index 0000000..3393916 --- /dev/null +++ b/src/Mapping/Transformer/GatewayNameMapTransformer.php @@ -0,0 +1,24 @@ +gatewayLocator->get($value); + + $resource = new GatewayApiResource(); + $resource->name = $gateway::getName(); + $resource->supports = $gateway::getSupportedChargeTypes(); + + return $resource; + } +} From bfbaa4aa13e0a99f7364a866b1b43a077e88f7c1 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 16 Jan 2025 12:08:46 +0100 Subject: [PATCH 56/76] Use mapping transformer for accounting resource balance --- .../Accounting/AccountingApiResource.php | 29 ++++++++++--------- .../AccountingBalanceMapTransformer.php | 22 ++++++++++++++ .../Accounting/AccountingStateProvider.php | 19 ++---------- 3 files changed, 40 insertions(+), 30 deletions(-) create mode 100644 src/Mapping/Transformer/AccountingBalanceMapTransformer.php diff --git a/src/ApiResource/Accounting/AccountingApiResource.php b/src/ApiResource/Accounting/AccountingApiResource.php index b46ab69..b206dcf 100644 --- a/src/ApiResource/Accounting/AccountingApiResource.php +++ b/src/ApiResource/Accounting/AccountingApiResource.php @@ -11,8 +11,10 @@ use App\Entity\Money; use App\Entity\Project\Project; use App\Entity\Tipjar; use App\Entity\User\User; +use App\Mapping\Transformer\AccountingBalanceMapTransformer; use App\State\Accounting\AccountingStateProcessor; use App\State\Accounting\AccountingStateProvider; +use AutoMapper\Attribute\MapFrom; /** * v4 features an advanced economy model under the hood. @@ -41,18 +43,15 @@ class AccountingApiResource */ public string $currency; + /** + * The money currently held by the Accounting. + */ + #[MapFrom(Accounting::class, transformer: AccountingBalanceMapTransformer::class)] + public Money $balance; + #[API\ApiProperty(readable: false, writable: false)] public string $ownerClass; - #[API\ApiProperty(readable: false, writable: false)] - public ?UserApiResource $user = null; - - #[API\ApiProperty(readable: false, writable: false)] - public ?ProjectApiResource $project = null; - - #[API\ApiProperty(readable: false, writable: false)] - public ?Tipjar $tipjar = null; - /** * The resource owning this Accounting. * @@ -70,8 +69,12 @@ class AccountingApiResource } } - /** - * The money currently held by the Accounting. - */ - public Money $balance; + #[API\ApiProperty(readable: false, writable: false)] + public ?UserApiResource $user = null; + + #[API\ApiProperty(readable: false, writable: false)] + public ?ProjectApiResource $project = null; + + #[API\ApiProperty(readable: false, writable: false)] + public ?Tipjar $tipjar = null; } diff --git a/src/Mapping/Transformer/AccountingBalanceMapTransformer.php b/src/Mapping/Transformer/AccountingBalanceMapTransformer.php new file mode 100644 index 0000000..c829b35 --- /dev/null +++ b/src/Mapping/Transformer/AccountingBalanceMapTransformer.php @@ -0,0 +1,22 @@ +accountingService->calcBalance($source); + } +} diff --git a/src/State/Accounting/AccountingStateProvider.php b/src/State/Accounting/AccountingStateProvider.php index 4c4e25a..fb4eb11 100644 --- a/src/State/Accounting/AccountingStateProvider.php +++ b/src/State/Accounting/AccountingStateProvider.php @@ -10,12 +10,6 @@ use ApiPlatform\Metadata\Operation; use ApiPlatform\State\Pagination\TraversablePaginator; use ApiPlatform\State\ProviderInterface; use App\ApiResource\Accounting\AccountingApiResource; -use App\ApiResource\Project\ProjectApiResource; -use App\ApiResource\User\UserApiResource; -use App\Entity\Accounting\Accounting; -use App\Entity\Project\Project; -use App\Entity\Tipjar; -use App\Entity\User\User; use App\Mapping\AutoMapper; use App\Service\AccountingService; use Symfony\Component\DependencyInjection\Attribute\Autowire; @@ -39,7 +33,7 @@ class AccountingStateProvider implements ProviderInterface $resources = []; foreach ($accountings as $accounting) { - $resources[] = $this->toResource($accounting); + $resources[] = $this->autoMapper->map($accounting, AccountingApiResource::class); } return new TraversablePaginator( @@ -56,15 +50,6 @@ class AccountingStateProvider implements ProviderInterface return null; } - return $this->toResource($accounting); - } - - private function toResource(Accounting $accounting): AccountingApiResource - { - /** @var AccountingApiResource */ - $resource = $this->autoMapper->map($accounting, AccountingApiResource::class); - $resource->balance = $this->accountingService->calcBalance($accounting); - - return $resource; + return $this->autoMapper->map($accounting, AccountingApiResource::class); } } From b9f9f0e71d5a4099259293e283cd0e55875d033d Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 16 Jan 2025 12:09:15 +0100 Subject: [PATCH 57/76] Line break after function --- src/Mapping/Transformer/GatewayNameMapTransformer.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mapping/Transformer/GatewayNameMapTransformer.php b/src/Mapping/Transformer/GatewayNameMapTransformer.php index 3393916..8f5b132 100644 --- a/src/Mapping/Transformer/GatewayNameMapTransformer.php +++ b/src/Mapping/Transformer/GatewayNameMapTransformer.php @@ -12,7 +12,8 @@ class GatewayNameMapTransformer implements PropertyTransformerInterface private GatewayLocator $gatewayLocator, ) {} - public function transform(mixed $value, object|array $source, array $context): mixed { + public function transform(mixed $value, object|array $source, array $context): mixed + { $gateway = $this->gatewayLocator->get($value); $resource = new GatewayApiResource(); From b6dd7f9cf27c5cd368b8e5d523617c060bdee8e8 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 16 Jan 2025 14:46:46 +0100 Subject: [PATCH 58/76] Feed same php version and extensions to php-actions composer and phpunit --- .github/workflows/phpunit.yaml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/phpunit.yaml b/.github/workflows/phpunit.yaml index 0122ac8..ca44169 100644 --- a/.github/workflows/phpunit.yaml +++ b/.github/workflows/phpunit.yaml @@ -1,5 +1,11 @@ name: PHPUnit + on: [push] + +env: + PHP_VERSION: '8.3' + PHP_EXTENSIONS: pdo_mysql + jobs: phpunit: runs-on: ubuntu-latest @@ -19,12 +25,15 @@ jobs: - uses: actions/checkout@v4 - uses: php-actions/composer@v6 + with: + php_version: ${{ env.PHP_VERSION }} + php_extensions: ${{ env.PHP_EXTENSIONS }} - name: PHPUnit uses: php-actions/phpunit@v4 env: DATABASE_URL: mysql://root:goteo@127.0.0.1:${{ job.services.mariadb.ports['3306'] }}/goteo with: - php_version: 8.3 - php_extensions: pdo_mysql + php_version: ${{ env.PHP_VERSION }} + php_extensions: ${{ env.PHP_EXTENSIONS }} configuration: phpunit.xml.dist From 9147bcc4dd1279109860e5ab01c7b3ccac3b331a Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 16 Jan 2025 15:02:35 +0100 Subject: [PATCH 59/76] Read stripe api key from secrets --- .github/workflows/phpunit.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/phpunit.yaml b/.github/workflows/phpunit.yaml index ca44169..82b84fe 100644 --- a/.github/workflows/phpunit.yaml +++ b/.github/workflows/phpunit.yaml @@ -25,6 +25,8 @@ jobs: - uses: actions/checkout@v4 - uses: php-actions/composer@v6 + env: + STRIPE_API_KEY: ${{ secrets.STRIPE_API_KEY }} with: php_version: ${{ env.PHP_VERSION }} php_extensions: ${{ env.PHP_EXTENSIONS }} From 84bfa13d2d6b82e870c386085a4f802e6d94f895 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 16 Jan 2025 15:10:42 +0100 Subject: [PATCH 60/76] Move STRIPE_API_KEY from steps to phpunit job --- .github/workflows/phpunit.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/phpunit.yaml b/.github/workflows/phpunit.yaml index 82b84fe..13bdff3 100644 --- a/.github/workflows/phpunit.yaml +++ b/.github/workflows/phpunit.yaml @@ -10,6 +10,9 @@ jobs: phpunit: runs-on: ubuntu-latest + env: + STRIPE_API_KEY: ${{ secrets.STRIPE_API_KEY }} + services: mariadb: image: mariadb:10.11.2 @@ -25,8 +28,6 @@ jobs: - uses: actions/checkout@v4 - uses: php-actions/composer@v6 - env: - STRIPE_API_KEY: ${{ secrets.STRIPE_API_KEY }} with: php_version: ${{ env.PHP_VERSION }} php_extensions: ${{ env.PHP_EXTENSIONS }} From a8a1d7ebd72fe7ba958cd8fee02f0ca6b77534ab Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Thu, 16 Jan 2025 15:36:46 +0100 Subject: [PATCH 61/76] Add intl to the list of php extensions --- .github/workflows/phpunit.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/phpunit.yaml b/.github/workflows/phpunit.yaml index 13bdff3..d4ca3cd 100644 --- a/.github/workflows/phpunit.yaml +++ b/.github/workflows/phpunit.yaml @@ -4,7 +4,7 @@ on: [push] env: PHP_VERSION: '8.3' - PHP_EXTENSIONS: pdo_mysql + PHP_EXTENSIONS: pdo_mysql intl jobs: phpunit: From 54d04aa4ee4b1d948cd1ab7e160e767576b9ff2a Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 12:44:38 +0100 Subject: [PATCH 62/76] Bump dependencies via composer update --- composer.lock | 1299 ++++++++++++++++++++++++------------------------- 1 file changed, 646 insertions(+), 653 deletions(-) diff --git a/composer.lock b/composer.lock index 5075c35..8824b6e 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "api-platform/core", - "version": "v3.4.4", + "version": "v3.4.15", "source": { "type": "git", "url": "https://github.com/api-platform/core.git", - "reference": "77d3ff3e8ddf88546eaf288a399d11f130553606" + "reference": "2055e08bca997a2707d7a3252c939953101de9c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/core/zipball/77d3ff3e8ddf88546eaf288a399d11f130553606", - "reference": "77d3ff3e8ddf88546eaf288a399d11f130553606", + "url": "https://api.github.com/repos/api-platform/core/zipball/2055e08bca997a2707d7a3252c939953101de9c8", + "reference": "2055e08bca997a2707d7a3252c939953101de9c8", "shasum": "" }, "require": { @@ -44,7 +44,7 @@ "elasticsearch/elasticsearch": ">=8.0,<8.4", "phpspec/prophecy": "<1.15", "phpunit/phpunit": "<9.5", - "symfony/framework-bundle": "6.4.6 || 7.1.6", + "symfony/framework-bundle": "6.4.6 || 7.0.6", "symfony/var-exporter": "<6.1.1" }, "replace": { @@ -107,7 +107,7 @@ "justinrainbow/json-schema": "^5.2.1", "phpspec/prophecy-phpunit": "^2.0", "phpstan/extension-installer": "^1.1", - "phpstan/phpdoc-parser": "^1.13", + "phpstan/phpdoc-parser": "^1.13|^2.0", "phpstan/phpstan": "^1.10", "phpstan/phpstan-doctrine": "^1.0", "phpstan/phpstan-phpunit": "^1.0", @@ -174,13 +174,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-3.4": "3.4.x-dev", - "dev-main": "4.0.x-dev" - }, - "symfony": { - "require": "^6.4 || ^7.1" - }, "pmu": { "projects": [ "./src/*/composer.json", @@ -188,8 +181,15 @@ ] }, "thanks": { - "name": "api-platform/api-platform", - "url": "https://github.com/api-platform/api-platform" + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.1" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" } }, "autoload": { @@ -223,9 +223,9 @@ ], "support": { "issues": "https://github.com/api-platform/core/issues", - "source": "https://github.com/api-platform/core/tree/v3.4.4" + "source": "https://github.com/api-platform/core/tree/v3.4.15" }, - "time": "2024-10-19T10:05:07+00:00" + "time": "2025-01-17T09:51:46+00:00" }, { "name": "beberlei/doctrineextensions", @@ -451,6 +451,87 @@ ], "time": "2023-09-23T21:17:11+00:00" }, + { + "name": "composer/semver", + "version": "3.4.3", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.3" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-09-19T14:15:21+00:00" + }, { "name": "doctrine/annotations", "version": "2.0.2", @@ -708,20 +789,20 @@ }, { "name": "doctrine/common", - "version": "3.4.5", + "version": "3.5.0", "source": { "type": "git", "url": "https://github.com/doctrine/common.git", - "reference": "6c8fef961f67b8bc802ce3e32e3ebd1022907286" + "reference": "d9ea4a54ca2586db781f0265d36bea731ac66ec5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/6c8fef961f67b8bc802ce3e32e3ebd1022907286", - "reference": "6c8fef961f67b8bc802ce3e32e3ebd1022907286", + "url": "https://api.github.com/repos/doctrine/common/zipball/d9ea4a54ca2586db781f0265d36bea731ac66ec5", + "reference": "d9ea4a54ca2586db781f0265d36bea731ac66ec5", "shasum": "" }, "require": { - "doctrine/persistence": "^2.0 || ^3.0", + "doctrine/persistence": "^2.0 || ^3.0 || ^4.0", "php": "^7.1 || ^8.0" }, "require-dev": { @@ -779,7 +860,7 @@ ], "support": { "issues": "https://github.com/doctrine/common/issues", - "source": "https://github.com/doctrine/common/tree/3.4.5" + "source": "https://github.com/doctrine/common/tree/3.5.0" }, "funding": [ { @@ -795,20 +876,20 @@ "type": "tidelift" } ], - "time": "2024-10-08T15:53:43+00:00" + "time": "2025-01-01T22:12:03+00:00" }, { "name": "doctrine/dbal", - "version": "3.9.3", + "version": "3.9.4", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "61446f07fcb522414d6cfd8b1c3e5f9e18c579ba" + "reference": "ec16c82f20be1a7224e65ac67144a29199f87959" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/61446f07fcb522414d6cfd8b1c3e5f9e18c579ba", - "reference": "61446f07fcb522414d6cfd8b1c3e5f9e18c579ba", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/ec16c82f20be1a7224e65ac67144a29199f87959", + "reference": "ec16c82f20be1a7224e65ac67144a29199f87959", "shasum": "" }, "require": { @@ -824,15 +905,13 @@ "doctrine/coding-standard": "12.0.0", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2023.1", - "phpstan/phpstan": "1.12.6", - "phpstan/phpstan-strict-rules": "^1.6", - "phpunit/phpunit": "9.6.20", - "psalm/plugin-phpunit": "0.18.4", + "phpstan/phpstan": "2.1.1", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "9.6.22", "slevomat/coding-standard": "8.13.1", "squizlabs/php_codesniffer": "3.10.2", "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/console": "^4.4|^5.4|^6.0|^7.0", - "vimeo/psalm": "4.30.0" + "symfony/console": "^4.4|^5.4|^6.0|^7.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -892,7 +971,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.9.3" + "source": "https://github.com/doctrine/dbal/tree/3.9.4" }, "funding": [ { @@ -908,33 +987,31 @@ "type": "tidelift" } ], - "time": "2024-10-10T17:56:43+00:00" + "time": "2025-01-16T08:28:55+00:00" }, { "name": "doctrine/deprecations", - "version": "1.1.3", + "version": "1.1.4", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" + "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", - "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/31610dbb31faa98e6b5447b62340826f54fbc4e9", + "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^9", - "phpstan/phpstan": "1.4.10 || 1.10.15", - "phpstan/phpstan-phpunit": "^1.0", + "doctrine/coding-standard": "^9 || ^12", + "phpstan/phpstan": "1.4.10 || 2.0.3", + "phpstan/phpstan-phpunit": "^1.0 || ^2", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psalm/plugin-phpunit": "0.18.4", - "psr/log": "^1 || ^2 || ^3", - "vimeo/psalm": "4.30.0 || 5.12.0" + "psr/log": "^1 || ^2 || ^3" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" @@ -942,7 +1019,7 @@ "type": "library", "autoload": { "psr-4": { - "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + "Doctrine\\Deprecations\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -953,22 +1030,22 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.3" + "source": "https://github.com/doctrine/deprecations/tree/1.1.4" }, - "time": "2024-01-30T19:34:25+00:00" + "time": "2024-12-07T21:18:45+00:00" }, { "name": "doctrine/doctrine-bundle", - "version": "2.13.0", + "version": "2.13.2", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "ca59d84b8e63143ce1aed90cdb333ba329d71563" + "reference": "2363c43d9815a11657e452625cd64172d5587486" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/ca59d84b8e63143ce1aed90cdb333ba329d71563", - "reference": "ca59d84b8e63143ce1aed90cdb333ba329d71563", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/2363c43d9815a11657e452625cd64172d5587486", + "reference": "2363c43d9815a11657e452625cd64172d5587486", "shasum": "" }, "require": { @@ -982,7 +1059,7 @@ "symfony/console": "^5.4 || ^6.0 || ^7.0", "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", "symfony/deprecation-contracts": "^2.1 || ^3", - "symfony/doctrine-bridge": "^5.4.19 || ^6.0.7 || ^7.0", + "symfony/doctrine-bridge": "^5.4.46 || ~6.3.12 || ^6.4.3 || ^7.0.3", "symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0", "symfony/polyfill-php80": "^1.15", "symfony/service-contracts": "^1.1.1 || ^2.0 || ^3" @@ -998,13 +1075,14 @@ "doctrine/deprecations": "^1.0", "doctrine/orm": "^2.17 || ^3.0", "friendsofphp/proxy-manager-lts": "^1.0", + "phpstan/phpstan": "2.1.1", + "phpstan/phpstan-phpunit": "2.0.3", + "phpstan/phpstan-strict-rules": "^2", "phpunit/phpunit": "^9.5.26", - "psalm/plugin-phpunit": "^0.18.4", - "psalm/plugin-symfony": "^5", "psr/log": "^1.1.4 || ^2.0 || ^3.0", "symfony/phpunit-bridge": "^6.1 || ^7.0", "symfony/property-info": "^5.4 || ^6.0 || ^7.0", - "symfony/proxy-manager-bridge": "^5.4 || ^6.0 || ^7.0", + "symfony/proxy-manager-bridge": "^5.4 || ^6.0", "symfony/security-bundle": "^5.4 || ^6.0 || ^7.0", "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0", "symfony/string": "^5.4 || ^6.0 || ^7.0", @@ -1013,8 +1091,7 @@ "symfony/var-exporter": "^5.4 || ^6.2 || ^7.0", "symfony/web-profiler-bundle": "^5.4 || ^6.0 || ^7.0", "symfony/yaml": "^5.4 || ^6.0 || ^7.0", - "twig/twig": "^1.34 || ^2.12 || ^3.0", - "vimeo/psalm": "^5.15" + "twig/twig": "^1.34 || ^2.12 || ^3.0" }, "suggest": { "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.", @@ -1059,7 +1136,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.13.0" + "source": "https://github.com/doctrine/DoctrineBundle/tree/2.13.2" }, "funding": [ { @@ -1075,26 +1152,26 @@ "type": "tidelift" } ], - "time": "2024-09-01T09:46:40+00:00" + "time": "2025-01-15T11:12:38+00:00" }, { "name": "doctrine/doctrine-migrations-bundle", - "version": "3.3.1", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineMigrationsBundle.git", - "reference": "715b62c31a5894afcb2b2cdbbc6607d7dd0580c0" + "reference": "a5c5fe0d2c6b911c03555046febb05a05a347078" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/715b62c31a5894afcb2b2cdbbc6607d7dd0580c0", - "reference": "715b62c31a5894afcb2b2cdbbc6607d7dd0580c0", + "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/a5c5fe0d2c6b911c03555046febb05a05a347078", + "reference": "a5c5fe0d2c6b911c03555046febb05a05a347078", "shasum": "" }, "require": { "doctrine/doctrine-bundle": "^2.4", "doctrine/migrations": "^3.2", - "php": "^7.2|^8.0", + "php": "^7.2 || ^8.0", "symfony/deprecation-contracts": "^2.1 || ^3", "symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0" }, @@ -1102,27 +1179,21 @@ "composer/semver": "^3.0", "doctrine/coding-standard": "^12", "doctrine/orm": "^2.6 || ^3", - "doctrine/persistence": "^2.0 || ^3 ", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-deprecation-rules": "^1", - "phpstan/phpstan-phpunit": "^1", - "phpstan/phpstan-strict-rules": "^1.1", - "phpstan/phpstan-symfony": "^1.3", - "phpunit/phpunit": "^8.5|^9.5", - "psalm/plugin-phpunit": "^0.18.4", - "psalm/plugin-symfony": "^3 || ^5", + "doctrine/persistence": "^2.0 || ^3", + "phpstan/phpstan": "^1.4 || ^2", + "phpstan/phpstan-deprecation-rules": "^1 || ^2", + "phpstan/phpstan-phpunit": "^1 || ^2", + "phpstan/phpstan-strict-rules": "^1.1 || ^2", + "phpstan/phpstan-symfony": "^1.3 || ^2", + "phpunit/phpunit": "^8.5 || ^9.5", "symfony/phpunit-bridge": "^6.3 || ^7", - "symfony/var-exporter": "^5.4 || ^6 || ^7", - "vimeo/psalm": "^4.30 || ^5.15" + "symfony/var-exporter": "^5.4 || ^6 || ^7" }, "type": "symfony-bundle", "autoload": { "psr-4": { - "Doctrine\\Bundle\\MigrationsBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Doctrine\\Bundle\\MigrationsBundle\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1151,7 +1222,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineMigrationsBundle/issues", - "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.3.1" + "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.4.0" }, "funding": [ { @@ -1167,7 +1238,7 @@ "type": "tidelift" } ], - "time": "2024-05-14T20:32:18+00:00" + "time": "2025-01-16T20:28:10+00:00" }, { "name": "doctrine/event-manager", @@ -1603,16 +1674,16 @@ }, { "name": "doctrine/orm", - "version": "2.20.0", + "version": "2.20.1", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "8ed6c2234aba019f9737a6bcc9516438e62da27c" + "reference": "e3cabade99ebccc6ba078884c1c5f250866a494e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/8ed6c2234aba019f9737a6bcc9516438e62da27c", - "reference": "8ed6c2234aba019f9737a6bcc9516438e62da27c", + "url": "https://api.github.com/repos/doctrine/orm/zipball/e3cabade99ebccc6ba078884c1c5f250866a494e", + "reference": "e3cabade99ebccc6ba078884c1c5f250866a494e", "shasum": "" }, "require": { @@ -1642,15 +1713,14 @@ "doctrine/coding-standard": "^9.0.2 || ^12.0", "phpbench/phpbench": "^0.16.10 || ^1.0", "phpstan/extension-installer": "~1.1.0 || ^1.4", - "phpstan/phpstan": "~1.4.10 || 1.12.6", - "phpstan/phpstan-deprecation-rules": "^1", + "phpstan/phpstan": "~1.4.10 || 2.0.3", + "phpstan/phpstan-deprecation-rules": "^1 || ^2", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6", "psr/log": "^1 || ^2 || ^3", "squizlabs/php_codesniffer": "3.7.2", "symfony/cache": "^4.4 || ^5.4 || ^6.4 || ^7.0", "symfony/var-exporter": "^4.4 || ^5.4 || ^6.2 || ^7.0", - "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0", - "vimeo/psalm": "4.30.0 || 5.24.0" + "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0" }, "suggest": { "ext-dom": "Provides support for XSD validation for XML mapping files", @@ -1700,22 +1770,22 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/2.20.0" + "source": "https://github.com/doctrine/orm/tree/2.20.1" }, - "time": "2024-10-11T11:47:24+00:00" + "time": "2024-12-19T06:48:36+00:00" }, { "name": "doctrine/persistence", - "version": "3.3.3", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "b337726451f5d530df338fc7f68dee8781b49779" + "reference": "0ea965320cec355dba75031c1b23d4c78362e3ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/b337726451f5d530df338fc7f68dee8781b49779", - "reference": "b337726451f5d530df338fc7f68dee8781b49779", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/0ea965320cec355dba75031c1b23d4c78362e3ff", + "reference": "0ea965320cec355dba75031c1b23d4c78362e3ff", "shasum": "" }, "require": { @@ -1729,12 +1799,11 @@ "require-dev": { "doctrine/coding-standard": "^12", "doctrine/common": "^3.0", - "phpstan/phpstan": "1.11.1", + "phpstan/phpstan": "1.12.7", "phpstan/phpstan-phpunit": "^1", "phpstan/phpstan-strict-rules": "^1.1", - "phpunit/phpunit": "^8.5 || ^9.5", - "symfony/cache": "^4.4 || ^5.4 || ^6.0", - "vimeo/psalm": "4.30.0 || 5.24.0" + "phpunit/phpunit": "^8.5.38 || ^9.5", + "symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0" }, "type": "library", "autoload": { @@ -1783,7 +1852,7 @@ ], "support": { "issues": "https://github.com/doctrine/persistence/issues", - "source": "https://github.com/doctrine/persistence/tree/3.3.3" + "source": "https://github.com/doctrine/persistence/tree/3.4.0" }, "funding": [ { @@ -1799,7 +1868,7 @@ "type": "tidelift" } ], - "time": "2024-06-20T10:14:30+00:00" + "time": "2024-10-30T19:48:12+00:00" }, { "name": "doctrine/sql-formatter", @@ -1859,22 +1928,25 @@ }, { "name": "doctrineencryptbundle/doctrine-encrypt-bundle", - "version": "5.4.1", + "version": "5.4.2", "source": { "type": "git", "url": "https://github.com/DoctrineEncryptBundle/DoctrineEncryptBundle.git", - "reference": "556c2ec0156d519378e6d62a61c2e924e4583e13" + "reference": "79f148a15b4b70fb1886b1ce9b4136f4c3a287b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/DoctrineEncryptBundle/DoctrineEncryptBundle/zipball/556c2ec0156d519378e6d62a61c2e924e4583e13", - "reference": "556c2ec0156d519378e6d62a61c2e924e4583e13", + "url": "https://api.github.com/repos/DoctrineEncryptBundle/DoctrineEncryptBundle/zipball/79f148a15b4b70fb1886b1ce9b4136f4c3a287b7", + "reference": "79f148a15b4b70fb1886b1ce9b4136f4c3a287b7", "shasum": "" }, "require": { + "composer-runtime-api": "^2.0", + "composer/semver": "^3.0", "doctrine/annotations": "^1.13|^2.0", + "doctrine/common": "^3.4", "doctrine/doctrine-bundle": "^2.0.8|^2.1", - "doctrine/orm": "^2.5", + "doctrine/orm": "^2.5|^3.3", "paragonie/halite": "^4.6|^5.0", "php": "^7.2|^8.0", "symfony/config": "^5.4|^6.0|^7.0", @@ -1887,6 +1959,7 @@ "require-dev": { "defuse/php-encryption": "^2.1", "doctrine/cache": "^1.11", + "friendsofphp/php-cs-fixer": "3.64.0", "jetbrains/phpstorm-attributes": "^1.0", "phpcompatibility/php-compatibility": "^9.3", "phpstan/phpstan": "^1.4", @@ -1918,9 +1991,9 @@ ], "support": { "issues": "https://github.com/DoctrineEncryptBundle/DoctrineEncryptBundle/issues", - "source": "https://github.com/DoctrineEncryptBundle/DoctrineEncryptBundle/tree/5.4.1" + "source": "https://github.com/DoctrineEncryptBundle/DoctrineEncryptBundle/tree/5.4.2" }, - "time": "2024-10-13T10:08:12+00:00" + "time": "2024-12-14T10:54:02+00:00" }, { "name": "gedmo/doctrine-extensions", @@ -2054,16 +2127,16 @@ }, { "name": "godruoyi/php-snowflake", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/godruoyi/php-snowflake.git", - "reference": "cbf44765679bd1e58f1c2ec0263eb340dd0d6f47" + "reference": "eacdba18c157aab2d567f499ca1865b7fff2bdfa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/godruoyi/php-snowflake/zipball/cbf44765679bd1e58f1c2ec0263eb340dd0d6f47", - "reference": "cbf44765679bd1e58f1c2ec0263eb340dd0d6f47", + "url": "https://api.github.com/repos/godruoyi/php-snowflake/zipball/eacdba18c157aab2d567f499ca1865b7fff2bdfa", + "reference": "eacdba18c157aab2d567f499ca1865b7fff2bdfa", "shasum": "" }, "require": { @@ -2109,7 +2182,7 @@ ], "support": { "issues": "https://github.com/godruoyi/php-snowflake/issues", - "source": "https://github.com/godruoyi/php-snowflake/tree/3.1.0" + "source": "https://github.com/godruoyi/php-snowflake/tree/3.1.1" }, "funding": [ { @@ -2117,7 +2190,7 @@ "type": "custom" } ], - "time": "2024-04-08T07:08:02+00:00" + "time": "2024-11-22T14:18:15+00:00" }, { "name": "jolicode/automapper", @@ -2207,16 +2280,16 @@ }, { "name": "monolog/monolog", - "version": "3.7.0", + "version": "3.8.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "f4393b648b78a5408747de94fca38beb5f7e9ef8" + "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f4393b648b78a5408747de94fca38beb5f7e9ef8", - "reference": "f4393b648b78a5408747de94fca38beb5f7e9ef8", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/aef6ee73a77a66e404dd6540934a9ef1b3c855b4", + "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4", "shasum": "" }, "require": { @@ -2236,12 +2309,14 @@ "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", - "phpstan/phpstan": "^1.9", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-strict-rules": "^1.4", - "phpunit/phpunit": "^10.5.17", + "php-console/php-console": "^3.1.8", + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.17 || ^11.0.7", "predis/predis": "^1.1 || ^2", - "ruflin/elastica": "^7", + "rollbar/rollbar": "^4.0", + "ruflin/elastica": "^7 || ^8", "symfony/mailer": "^5.4 || ^6", "symfony/mime": "^5.4 || ^6" }, @@ -2292,7 +2367,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.7.0" + "source": "https://github.com/Seldaek/monolog/tree/3.8.1" }, "funding": [ { @@ -2304,7 +2379,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T09:40:51+00:00" + "time": "2024-12-05T17:15:07+00:00" }, { "name": "nelmio/cors-bundle", @@ -2370,16 +2445,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.3.1", + "version": "v5.4.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", - "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", "shasum": "" }, "require": { @@ -2422,9 +2497,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" }, - "time": "2024-10-08T18:51:32+00:00" + "time": "2024-12-30T11:07:19+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -2762,16 +2837,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.4.1", + "version": "5.6.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c" + "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", - "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8", + "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8", "shasum": "" }, "require": { @@ -2780,17 +2855,17 @@ "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.2", "phpdocumentor/type-resolver": "^1.7", - "phpstan/phpdoc-parser": "^1.7", + "phpstan/phpdoc-parser": "^1.7|^2.0", "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.5", + "mockery/mockery": "~1.3.5 || ~1.6.0", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.8", "phpstan/phpstan-mockery": "^1.1", "phpstan/phpstan-webmozart-assert": "^1.2", "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^5.13" + "psalm/phar": "^5.26" }, "type": "library", "extra": { @@ -2820,29 +2895,29 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.1" }, - "time": "2024-05-21T05:55:05+00:00" + "time": "2024-12-07T09:39:29+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.8.2", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "153ae662783729388a584b4361f2545e4d841e3c" + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c", - "reference": "153ae662783729388a584b4361f2545e4d841e3c", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a", "shasum": "" }, "require": { "doctrine/deprecations": "^1.0", "php": "^7.3 || ^8.0", "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.13" + "phpstan/phpdoc-parser": "^1.18|^2.0" }, "require-dev": { "ext-tokenizer": "*", @@ -2878,9 +2953,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0" }, - "time": "2024-02-23T11:10:43+00:00" + "time": "2024-11-09T15:12:26+00:00" }, { "name": "phpstan/phpdoc-parser", @@ -3237,16 +3312,16 @@ }, { "name": "stof/doctrine-extensions-bundle", - "version": "v1.12.0", + "version": "v1.13.0", "source": { "type": "git", "url": "https://github.com/stof/StofDoctrineExtensionsBundle.git", - "reference": "473ae65598fa4160654c350e139e20ee75d9a91a" + "reference": "bf00701bff3f2b7c4bf6d963101c9ea6968d694f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stof/StofDoctrineExtensionsBundle/zipball/473ae65598fa4160654c350e139e20ee75d9a91a", - "reference": "473ae65598fa4160654c350e139e20ee75d9a91a", + "url": "https://api.github.com/repos/stof/StofDoctrineExtensionsBundle/zipball/bf00701bff3f2b7c4bf6d963101c9ea6968d694f", + "reference": "bf00701bff3f2b7c4bf6d963101c9ea6968d694f", "shasum": "" }, "require": { @@ -3311,9 +3386,9 @@ ], "support": { "issues": "https://github.com/stof/StofDoctrineExtensionsBundle/issues", - "source": "https://github.com/stof/StofDoctrineExtensionsBundle/tree/v1.12.0" + "source": "https://github.com/stof/StofDoctrineExtensionsBundle/tree/v1.13.0" }, - "time": "2024-06-10T12:27:27+00:00" + "time": "2025-01-07T08:10:54+00:00" }, { "name": "stripe/stripe-php", @@ -3420,16 +3495,16 @@ }, { "name": "symfony/asset", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "c668aa320e26b7379540368832b9d1dd43d32603" + "reference": "2466c17d61d14539cddf77e57ebb9cc971185302" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/c668aa320e26b7379540368832b9d1dd43d32603", - "reference": "c668aa320e26b7379540368832b9d1dd43d32603", + "url": "https://api.github.com/repos/symfony/asset/zipball/2466c17d61d14539cddf77e57ebb9cc971185302", + "reference": "2466c17d61d14539cddf77e57ebb9cc971185302", "shasum": "" }, "require": { @@ -3469,7 +3544,7 @@ "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset/tree/v6.4.8" + "source": "https://github.com/symfony/asset/tree/v6.4.13" }, "funding": [ { @@ -3485,20 +3560,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "symfony/cache", - "version": "v6.4.12", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "a463451b7f6ac4a47b98dbfc78ec2d3560c759d8" + "reference": "70d60e9a3603108563010f8592dff15a6f15dfae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/a463451b7f6ac4a47b98dbfc78ec2d3560c759d8", - "reference": "a463451b7f6ac4a47b98dbfc78ec2d3560c759d8", + "url": "https://api.github.com/repos/symfony/cache/zipball/70d60e9a3603108563010f8592dff15a6f15dfae", + "reference": "70d60e9a3603108563010f8592dff15a6f15dfae", "shasum": "" }, "require": { @@ -3565,7 +3640,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.12" + "source": "https://github.com/symfony/cache/tree/v6.4.16" }, "funding": [ { @@ -3581,20 +3656,20 @@ "type": "tidelift" } ], - "time": "2024-09-16T16:01:33+00:00" + "time": "2024-11-20T10:10:54+00:00" }, { "name": "symfony/cache-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/cache-contracts.git", - "reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197" + "reference": "15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/df6a1a44c890faded49a5fca33c2d5c5fd3c2197", - "reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b", + "reference": "15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b", "shasum": "" }, "require": { @@ -3603,12 +3678,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -3641,7 +3716,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/cache-contracts/tree/v3.5.1" }, "funding": [ { @@ -3657,20 +3732,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/clock", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "7a4840efd17135cbd547e41ec49fb910ed4f8b98" + "reference": "b2bf55c4dd115003309eafa87ee7df9ed3dde81b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/7a4840efd17135cbd547e41ec49fb910ed4f8b98", - "reference": "7a4840efd17135cbd547e41ec49fb910ed4f8b98", + "url": "https://api.github.com/repos/symfony/clock/zipball/b2bf55c4dd115003309eafa87ee7df9ed3dde81b", + "reference": "b2bf55c4dd115003309eafa87ee7df9ed3dde81b", "shasum": "" }, "require": { @@ -3715,7 +3790,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v6.4.8" + "source": "https://github.com/symfony/clock/tree/v6.4.13" }, "funding": [ { @@ -3731,20 +3806,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:51:39+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/config", - "version": "v6.4.8", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "12e7e52515ce37191b193cf3365903c4f3951e35" + "reference": "4e55e7e4ffddd343671ea972216d4509f46c22ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/12e7e52515ce37191b193cf3365903c4f3951e35", - "reference": "12e7e52515ce37191b193cf3365903c4f3951e35", + "url": "https://api.github.com/repos/symfony/config/zipball/4e55e7e4ffddd343671ea972216d4509f46c22ef", + "reference": "4e55e7e4ffddd343671ea972216d4509f46c22ef", "shasum": "" }, "require": { @@ -3790,7 +3865,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v6.4.8" + "source": "https://github.com/symfony/config/tree/v6.4.14" }, "funding": [ { @@ -3806,20 +3881,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-11-04T11:33:53+00:00" }, { "name": "symfony/console", - "version": "v6.4.12", + "version": "v6.4.17", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "72d080eb9edf80e36c19be61f72c98ed8273b765" + "reference": "799445db3f15768ecc382ac5699e6da0520a0a04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/72d080eb9edf80e36c19be61f72c98ed8273b765", - "reference": "72d080eb9edf80e36c19be61f72c98ed8273b765", + "url": "https://api.github.com/repos/symfony/console/zipball/799445db3f15768ecc382ac5699e6da0520a0a04", + "reference": "799445db3f15768ecc382ac5699e6da0520a0a04", "shasum": "" }, "require": { @@ -3884,7 +3959,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.12" + "source": "https://github.com/symfony/console/tree/v6.4.17" }, "funding": [ { @@ -3900,20 +3975,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:15:52+00:00" + "time": "2024-12-07T12:07:30+00:00" }, { "name": "symfony/dependency-injection", - "version": "v6.4.12", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "cfb9d34a1cdd4911bc737a5358fd1cf8ebfb536e" + "reference": "7a379d8871f6a36f01559c14e11141cc02eb8dc8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/cfb9d34a1cdd4911bc737a5358fd1cf8ebfb536e", - "reference": "cfb9d34a1cdd4911bc737a5358fd1cf8ebfb536e", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/7a379d8871f6a36f01559c14e11141cc02eb8dc8", + "reference": "7a379d8871f6a36f01559c14e11141cc02eb8dc8", "shasum": "" }, "require": { @@ -3965,7 +4040,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.4.12" + "source": "https://github.com/symfony/dependency-injection/tree/v6.4.16" }, "funding": [ { @@ -3981,20 +4056,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:18:25+00:00" + "time": "2024-11-25T14:52:46+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", - "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", "shasum": "" }, "require": { @@ -4002,12 +4077,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -4032,7 +4107,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" }, "funding": [ { @@ -4048,20 +4123,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/doctrine-bridge", - "version": "v6.4.12", + "version": "v6.4.17", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "b5c0a0172bbe9b1435181d94ca5cbe4af3fb45af" + "reference": "2ba7e747a944b69f9f583c35173560afebbff995" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/b5c0a0172bbe9b1435181d94ca5cbe4af3fb45af", - "reference": "b5c0a0172bbe9b1435181d94ca5cbe4af3fb45af", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/2ba7e747a944b69f9f583c35173560afebbff995", + "reference": "2ba7e747a944b69f9f583c35173560afebbff995", "shasum": "" }, "require": { @@ -4091,7 +4166,7 @@ }, "require-dev": { "doctrine/collections": "^1.0|^2.0", - "doctrine/data-fixtures": "^1.1", + "doctrine/data-fixtures": "^1.1|^2", "doctrine/dbal": "^2.13.1|^3|^4", "doctrine/orm": "^2.15|^3", "psr/log": "^1|^2|^3", @@ -4140,7 +4215,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v6.4.12" + "source": "https://github.com/symfony/doctrine-bridge/tree/v6.4.17" }, "funding": [ { @@ -4156,20 +4231,20 @@ "type": "tidelift" } ], - "time": "2024-09-08T12:31:10+00:00" + "time": "2024-12-18T10:42:42+00:00" }, { "name": "symfony/dotenv", - "version": "v6.4.12", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "815284236cab7d8e1280f53bf562c07a4dfe5954" + "reference": "1ac5e7e7e862d4d574258daf08bd569ba926e4a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/815284236cab7d8e1280f53bf562c07a4dfe5954", - "reference": "815284236cab7d8e1280f53bf562c07a4dfe5954", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/1ac5e7e7e862d4d574258daf08bd569ba926e4a5", + "reference": "1ac5e7e7e862d4d574258daf08bd569ba926e4a5", "shasum": "" }, "require": { @@ -4214,7 +4289,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v6.4.12" + "source": "https://github.com/symfony/dotenv/tree/v6.4.16" }, "funding": [ { @@ -4230,20 +4305,20 @@ "type": "tidelift" } ], - "time": "2024-09-16T16:01:33+00:00" + "time": "2024-11-27T11:08:19+00:00" }, { "name": "symfony/error-handler", - "version": "v6.4.10", + "version": "v6.4.17", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "231f1b2ee80f72daa1972f7340297d67439224f0" + "reference": "37ad2380e8c1a8cf62a1200a5c10080b679b446c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/231f1b2ee80f72daa1972f7340297d67439224f0", - "reference": "231f1b2ee80f72daa1972f7340297d67439224f0", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/37ad2380e8c1a8cf62a1200a5c10080b679b446c", + "reference": "37ad2380e8c1a8cf62a1200a5c10080b679b446c", "shasum": "" }, "require": { @@ -4289,7 +4364,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.4.10" + "source": "https://github.com/symfony/error-handler/tree/v6.4.17" }, "funding": [ { @@ -4305,20 +4380,20 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:30:32+00:00" + "time": "2024-12-06T13:30:51+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "8d7507f02b06e06815e56bb39aa0128e3806208b" + "reference": "0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8d7507f02b06e06815e56bb39aa0128e3806208b", - "reference": "8d7507f02b06e06815e56bb39aa0128e3806208b", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e", + "reference": "0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e", "shasum": "" }, "require": { @@ -4369,7 +4444,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.8" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.13" }, "funding": [ { @@ -4385,20 +4460,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50" + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8f93aec25d41b72493c6ddff14e916177c9efc50", - "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", "shasum": "" }, "require": { @@ -4407,12 +4482,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -4445,7 +4520,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" }, "funding": [ { @@ -4461,20 +4536,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/expression-language", - "version": "v6.4.11", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "564e109c40d3637053c942a29a58e9434592a8bf" + "reference": "3524904fb026356a5230cd197f9a4e6a61e0e7df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/564e109c40d3637053c942a29a58e9434592a8bf", - "reference": "564e109c40d3637053c942a29a58e9434592a8bf", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/3524904fb026356a5230cd197f9a4e6a61e0e7df", + "reference": "3524904fb026356a5230cd197f9a4e6a61e0e7df", "shasum": "" }, "require": { @@ -4509,7 +4584,7 @@ "description": "Provides an engine that can compile and evaluate expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v6.4.11" + "source": "https://github.com/symfony/expression-language/tree/v6.4.13" }, "funding": [ { @@ -4525,20 +4600,20 @@ "type": "tidelift" } ], - "time": "2024-08-12T09:55:28+00:00" + "time": "2024-10-09T08:40:40+00:00" }, { "name": "symfony/filesystem", - "version": "v6.4.12", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "f810e3cbdf7fdc35983968523d09f349fa9ada12" + "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/f810e3cbdf7fdc35983968523d09f349fa9ada12", - "reference": "f810e3cbdf7fdc35983968523d09f349fa9ada12", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/4856c9cf585d5a0313d8d35afd681a526f038dd3", + "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3", "shasum": "" }, "require": { @@ -4575,7 +4650,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.12" + "source": "https://github.com/symfony/filesystem/tree/v6.4.13" }, "funding": [ { @@ -4591,20 +4666,20 @@ "type": "tidelift" } ], - "time": "2024-09-16T16:01:33+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "symfony/finder", - "version": "v6.4.11", + "version": "v6.4.17", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "d7eb6daf8cd7e9ac4976e9576b32042ef7253453" + "reference": "1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/d7eb6daf8cd7e9ac4976e9576b32042ef7253453", - "reference": "d7eb6daf8cd7e9ac4976e9576b32042ef7253453", + "url": "https://api.github.com/repos/symfony/finder/zipball/1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7", + "reference": "1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7", "shasum": "" }, "require": { @@ -4639,7 +4714,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.11" + "source": "https://github.com/symfony/finder/tree/v6.4.17" }, "funding": [ { @@ -4655,7 +4730,7 @@ "type": "tidelift" } ], - "time": "2024-08-13T14:27:37+00:00" + "time": "2024-12-29T13:51:37+00:00" }, { "name": "symfony/flex", @@ -4727,16 +4802,16 @@ }, { "name": "symfony/framework-bundle", - "version": "v6.4.12", + "version": "v6.4.17", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "6a9665bd1fae37b198429775c6132f193339434f" + "reference": "17d8ae2e7aa77154f942e8ac48849ac718b0963f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/6a9665bd1fae37b198429775c6132f193339434f", - "reference": "6a9665bd1fae37b198429775c6132f193339434f", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/17d8ae2e7aa77154f942e8ac48849ac718b0963f", + "reference": "17d8ae2e7aa77154f942e8ac48849ac718b0963f", "shasum": "" }, "require": { @@ -4775,6 +4850,7 @@ "symfony/mime": "<6.4", "symfony/property-access": "<5.4", "symfony/property-info": "<5.4", + "symfony/runtime": "<5.4.45|>=6.0,<6.4.13|>=7.0,<7.1.6", "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4", "symfony/security-core": "<5.4", "symfony/security-csrf": "<5.4", @@ -4855,7 +4931,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v6.4.12" + "source": "https://github.com/symfony/framework-bundle/tree/v6.4.17" }, "funding": [ { @@ -4871,27 +4947,27 @@ "type": "tidelift" } ], - "time": "2024-09-20T13:34:56+00:00" + "time": "2024-12-19T14:08:41+00:00" }, { "name": "symfony/http-client", - "version": "v6.4.12", + "version": "v6.4.17", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "fbebfcce21084d3e91ea987ae5bdd8c71ff0fd56" + "reference": "88898d842eb29d7e1a903724c94e90a6ca9c0509" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/fbebfcce21084d3e91ea987ae5bdd8c71ff0fd56", - "reference": "fbebfcce21084d3e91ea987ae5bdd8c71ff0fd56", + "url": "https://api.github.com/repos/symfony/http-client/zipball/88898d842eb29d7e1a903724c94e90a6ca9c0509", + "reference": "88898d842eb29d7e1a903724c94e90a6ca9c0509", "shasum": "" }, "require": { "php": ">=8.1", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "^3.4.1", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -4948,7 +5024,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.12" + "source": "https://github.com/symfony/http-client/tree/v6.4.17" }, "funding": [ { @@ -4964,20 +5040,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:21:33+00:00" + "time": "2024-12-18T12:18:31+00:00" }, { "name": "symfony/http-client-contracts", - "version": "v3.5.0", + "version": "v3.5.2", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "20414d96f391677bf80078aa55baece78b82647d" + "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d", - "reference": "20414d96f391677bf80078aa55baece78b82647d", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645", + "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645", "shasum": "" }, "require": { @@ -4985,12 +5061,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -5026,7 +5102,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2" }, "funding": [ { @@ -5042,20 +5118,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-12-07T08:49:48+00:00" }, { "name": "symfony/http-foundation", - "version": "v6.4.12", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "133ac043875f59c26c55e79cf074562127cce4d2" + "reference": "431771b7a6f662f1575b3cfc8fd7617aa9864d57" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/133ac043875f59c26c55e79cf074562127cce4d2", - "reference": "133ac043875f59c26c55e79cf074562127cce4d2", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/431771b7a6f662f1575b3cfc8fd7617aa9864d57", + "reference": "431771b7a6f662f1575b3cfc8fd7617aa9864d57", "shasum": "" }, "require": { @@ -5065,12 +5141,12 @@ "symfony/polyfill-php83": "^1.27" }, "conflict": { - "symfony/cache": "<6.3" + "symfony/cache": "<6.4.12|>=7.0,<7.1.5" }, "require-dev": { "doctrine/dbal": "^2.13.1|^3|^4", "predis/predis": "^1.1|^2.0", - "symfony/cache": "^6.3|^7.0", + "symfony/cache": "^6.4.12|^7.1.5", "symfony/dependency-injection": "^5.4|^6.0|^7.0", "symfony/expression-language": "^5.4|^6.0|^7.0", "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4|^7.0", @@ -5103,7 +5179,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.4.12" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.16" }, "funding": [ { @@ -5119,20 +5195,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:18:25+00:00" + "time": "2024-11-13T18:58:10+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.4.12", + "version": "v6.4.17", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "96df83d51b5f78804f70c093b97310794fd6257b" + "reference": "c5647393c5ce11833d13e4b70fff4b571d4ac710" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/96df83d51b5f78804f70c093b97310794fd6257b", - "reference": "96df83d51b5f78804f70c093b97310794fd6257b", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/c5647393c5ce11833d13e4b70fff4b571d4ac710", + "reference": "c5647393c5ce11833d13e4b70fff4b571d4ac710", "shasum": "" }, "require": { @@ -5217,7 +5293,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.4.12" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.17" }, "funding": [ { @@ -5233,20 +5309,20 @@ "type": "tidelift" } ], - "time": "2024-09-21T06:02:57+00:00" + "time": "2024-12-31T14:49:31+00:00" }, { "name": "symfony/intl", - "version": "v6.4.12", + "version": "v6.4.15", "source": { "type": "git", "url": "https://github.com/symfony/intl.git", - "reference": "5f64d7218f4078492ca59da94747d7474a2a52c4" + "reference": "b1d5e8d82615b60f229216edfee0b59e2ef66da6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/5f64d7218f4078492ca59da94747d7474a2a52c4", - "reference": "5f64d7218f4078492ca59da94747d7474a2a52c4", + "url": "https://api.github.com/repos/symfony/intl/zipball/b1d5e8d82615b60f229216edfee0b59e2ef66da6", + "reference": "b1d5e8d82615b60f229216edfee0b59e2ef66da6", "shasum": "" }, "require": { @@ -5300,7 +5376,7 @@ "localization" ], "support": { - "source": "https://github.com/symfony/intl/tree/v6.4.12" + "source": "https://github.com/symfony/intl/tree/v6.4.15" }, "funding": [ { @@ -5316,7 +5392,7 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:16:53+00:00" + "time": "2024-11-08T15:28:48+00:00" }, { "name": "symfony/lock", @@ -5399,16 +5475,16 @@ }, { "name": "symfony/monolog-bridge", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "0fbee64913b1c595e7650a1919ba3edba8d49ea7" + "reference": "9d14621e59f22c2b6d030d92d37ffe5ae1e60452" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/0fbee64913b1c595e7650a1919ba3edba8d49ea7", - "reference": "0fbee64913b1c595e7650a1919ba3edba8d49ea7", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/9d14621e59f22c2b6d030d92d37ffe5ae1e60452", + "reference": "9d14621e59f22c2b6d030d92d37ffe5ae1e60452", "shasum": "" }, "require": { @@ -5458,7 +5534,7 @@ "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v6.4.8" + "source": "https://github.com/symfony/monolog-bridge/tree/v6.4.13" }, "funding": [ { @@ -5474,7 +5550,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-10-14T08:49:08+00:00" }, { "name": "symfony/monolog-bundle", @@ -5559,16 +5635,16 @@ }, { "name": "symfony/password-hasher", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "90ebbe946e5d64a5fad9ac9427e335045cf2bd31" + "reference": "e97a1b31f60b8bdfc1fdedab4398538da9441d47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/90ebbe946e5d64a5fad9ac9427e335045cf2bd31", - "reference": "90ebbe946e5d64a5fad9ac9427e335045cf2bd31", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/e97a1b31f60b8bdfc1fdedab4398538da9441d47", + "reference": "e97a1b31f60b8bdfc1fdedab4398538da9441d47", "shasum": "" }, "require": { @@ -5611,7 +5687,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v6.4.8" + "source": "https://github.com/symfony/password-hasher/tree/v6.4.13" }, "funding": [ { @@ -5627,7 +5703,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -5652,8 +5728,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -5730,8 +5806,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -5814,8 +5890,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -5888,8 +5964,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -5946,16 +6022,16 @@ }, { "name": "symfony/property-access", - "version": "v6.4.11", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "866f6cd84f2094cbc6f66ce9752faf749916e2a9" + "reference": "8cc779d88d12e440adaa26387bcfc25744064afe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/866f6cd84f2094cbc6f66ce9752faf749916e2a9", - "reference": "866f6cd84f2094cbc6f66ce9752faf749916e2a9", + "url": "https://api.github.com/repos/symfony/property-access/zipball/8cc779d88d12e440adaa26387bcfc25744064afe", + "reference": "8cc779d88d12e440adaa26387bcfc25744064afe", "shasum": "" }, "require": { @@ -6003,7 +6079,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v6.4.11" + "source": "https://github.com/symfony/property-access/tree/v6.4.13" }, "funding": [ { @@ -6019,20 +6095,20 @@ "type": "tidelift" } ], - "time": "2024-08-30T16:10:11+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/property-info", - "version": "v6.4.10", + "version": "v6.4.17", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "edaea9dcc723cb4a0ab6a00f7d6f8c07c0d8ff77" + "reference": "38b125d78e67668159f75383a293ec0c5d3f2963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/edaea9dcc723cb4a0ab6a00f7d6f8c07c0d8ff77", - "reference": "edaea9dcc723cb4a0ab6a00f7d6f8c07c0d8ff77", + "url": "https://api.github.com/repos/symfony/property-info/zipball/38b125d78e67668159f75383a293ec0c5d3f2963", + "reference": "38b125d78e67668159f75383a293ec0c5d3f2963", "shasum": "" }, "require": { @@ -6040,17 +6116,18 @@ "symfony/string": "^5.4|^6.0|^7.0" }, "conflict": { + "doctrine/annotations": "<1.12", "phpdocumentor/reflection-docblock": "<5.2", "phpdocumentor/type-resolver": "<1.5.1", - "symfony/dependency-injection": "<5.4", - "symfony/serializer": "<6.4" + "symfony/dependency-injection": "<5.4|>=6.0,<6.4" }, "require-dev": { + "doctrine/annotations": "^1.12|^2", "phpdocumentor/reflection-docblock": "^5.2", - "phpstan/phpdoc-parser": "^1.0", + "phpstan/phpdoc-parser": "^1.0|^2.0", "symfony/cache": "^5.4|^6.0|^7.0", "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.4|^7.0" + "symfony/serializer": "^5.4|^6.4|^7.0" }, "type": "library", "autoload": { @@ -6086,7 +6163,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v6.4.10" + "source": "https://github.com/symfony/property-info/tree/v6.4.17" }, "funding": [ { @@ -6102,20 +6179,20 @@ "type": "tidelift" } ], - "time": "2024-07-26T07:32:07+00:00" + "time": "2024-12-26T19:01:29+00:00" }, { "name": "symfony/routing", - "version": "v6.4.12", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "a7c8036bd159486228dc9be3e846a00a0dda9f9f" + "reference": "91e02e606b4b705c2f4fb42f7e7708b7923a3220" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/a7c8036bd159486228dc9be3e846a00a0dda9f9f", - "reference": "a7c8036bd159486228dc9be3e846a00a0dda9f9f", + "url": "https://api.github.com/repos/symfony/routing/zipball/91e02e606b4b705c2f4fb42f7e7708b7923a3220", + "reference": "91e02e606b4b705c2f4fb42f7e7708b7923a3220", "shasum": "" }, "require": { @@ -6169,7 +6246,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.4.12" + "source": "https://github.com/symfony/routing/tree/v6.4.16" }, "funding": [ { @@ -6185,20 +6262,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:32:26+00:00" + "time": "2024-11-13T15:31:34+00:00" }, { "name": "symfony/runtime", - "version": "v6.4.12", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/runtime.git", - "reference": "bfe32a1adf41da4dd7f6b939a039779d7af5497f" + "reference": "4facd4174f45cd37c65860403412b67c7381136a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/runtime/zipball/bfe32a1adf41da4dd7f6b939a039779d7af5497f", - "reference": "bfe32a1adf41da4dd7f6b939a039779d7af5497f", + "url": "https://api.github.com/repos/symfony/runtime/zipball/4facd4174f45cd37c65860403412b67c7381136a", + "reference": "4facd4174f45cd37c65860403412b67c7381136a", "shasum": "" }, "require": { @@ -6248,7 +6325,7 @@ "runtime" ], "support": { - "source": "https://github.com/symfony/runtime/tree/v6.4.12" + "source": "https://github.com/symfony/runtime/tree/v6.4.14" }, "funding": [ { @@ -6264,20 +6341,20 @@ "type": "tidelift" } ], - "time": "2024-09-19T13:29:10+00:00" + "time": "2024-11-05T16:39:55+00:00" }, { "name": "symfony/security-bundle", - "version": "v6.4.11", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "620be16fceded671823ce6332d06f44bb327096d" + "reference": "181d1fcf5f88ef8212ed7f6434e5ff51c9d7dff3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/620be16fceded671823ce6332d06f44bb327096d", - "reference": "620be16fceded671823ce6332d06f44bb327096d", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/181d1fcf5f88ef8212ed7f6434e5ff51c9d7dff3", + "reference": "181d1fcf5f88ef8212ed7f6434e5ff51c9d7dff3", "shasum": "" }, "require": { @@ -6360,7 +6437,7 @@ "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-bundle/tree/v6.4.11" + "source": "https://github.com/symfony/security-bundle/tree/v6.4.13" }, "funding": [ { @@ -6376,20 +6453,20 @@ "type": "tidelift" } ], - "time": "2024-08-20T11:22:16+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/security-core", - "version": "v6.4.12", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "8c7e52155262b3ef6b7885f6d9bd90fb24eaa66f" + "reference": "19cdb7de86e556202ab16e0cffd1a97348231bc0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/8c7e52155262b3ef6b7885f6d9bd90fb24eaa66f", - "reference": "8c7e52155262b3ef6b7885f6d9bd90fb24eaa66f", + "url": "https://api.github.com/repos/symfony/security-core/zipball/19cdb7de86e556202ab16e0cffd1a97348231bc0", + "reference": "19cdb7de86e556202ab16e0cffd1a97348231bc0", "shasum": "" }, "require": { @@ -6446,7 +6523,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v6.4.12" + "source": "https://github.com/symfony/security-core/tree/v6.4.16" }, "funding": [ { @@ -6462,20 +6539,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:21:33+00:00" + "time": "2024-11-27T09:48:51+00:00" }, { "name": "symfony/security-csrf", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "f46ab02b76311087873257071559edcaf6d7ab99" + "reference": "c34421b7d34efbaef5d611ab2e646a0ec464ffe3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/f46ab02b76311087873257071559edcaf6d7ab99", - "reference": "f46ab02b76311087873257071559edcaf6d7ab99", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/c34421b7d34efbaef5d611ab2e646a0ec464ffe3", + "reference": "c34421b7d34efbaef5d611ab2e646a0ec464ffe3", "shasum": "" }, "require": { @@ -6514,7 +6591,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v6.4.8" + "source": "https://github.com/symfony/security-csrf/tree/v6.4.13" }, "funding": [ { @@ -6530,20 +6607,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/security-http", - "version": "v6.4.12", + "version": "v6.4.15", "source": { "type": "git", "url": "https://github.com/symfony/security-http.git", - "reference": "f6df97af71943cda726dc852335204eac02a716b" + "reference": "ded1e078f952e686b058d9eac98e497bea47b308" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/f6df97af71943cda726dc852335204eac02a716b", - "reference": "f6df97af71943cda726dc852335204eac02a716b", + "url": "https://api.github.com/repos/symfony/security-http/zipball/ded1e078f952e686b058d9eac98e497bea47b308", + "reference": "ded1e078f952e686b058d9eac98e497bea47b308", "shasum": "" }, "require": { @@ -6602,7 +6679,7 @@ "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-http/tree/v6.4.12" + "source": "https://github.com/symfony/security-http/tree/v6.4.15" }, "funding": [ { @@ -6618,20 +6695,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:18:25+00:00" + "time": "2024-11-13T13:40:18+00:00" }, { "name": "symfony/serializer", - "version": "v6.4.12", + "version": "v6.4.15", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "10ae9c1b90f4809ccb7277cc8fe8d80b3af4412c" + "reference": "9d862d66198f3c2e30404228629ef4c18d5d608e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/10ae9c1b90f4809ccb7277cc8fe8d80b3af4412c", - "reference": "10ae9c1b90f4809ccb7277cc8fe8d80b3af4412c", + "url": "https://api.github.com/repos/symfony/serializer/zipball/9d862d66198f3c2e30404228629ef4c18d5d608e", + "reference": "9d862d66198f3c2e30404228629ef4c18d5d608e", "shasum": "" }, "require": { @@ -6700,7 +6777,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v6.4.12" + "source": "https://github.com/symfony/serializer/tree/v6.4.15" }, "funding": [ { @@ -6716,20 +6793,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:15:52+00:00" + "time": "2024-10-23T13:25:59+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", - "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", "shasum": "" }, "require": { @@ -6742,12 +6819,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -6783,7 +6860,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" }, "funding": [ { @@ -6799,20 +6876,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/stopwatch", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "63e069eb616049632cde9674c46957819454b8aa" + "reference": "2cae0a6f8d04937d02f6d19806251e2104d54f92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/63e069eb616049632cde9674c46957819454b8aa", - "reference": "63e069eb616049632cde9674c46957819454b8aa", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/2cae0a6f8d04937d02f6d19806251e2104d54f92", + "reference": "2cae0a6f8d04937d02f6d19806251e2104d54f92", "shasum": "" }, "require": { @@ -6845,7 +6922,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v6.4.8" + "source": "https://github.com/symfony/stopwatch/tree/v6.4.13" }, "funding": [ { @@ -6861,20 +6938,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/string", - "version": "v6.4.12", + "version": "v6.4.15", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f8a1ccebd0997e16112dfecfd74220b78e5b284b" + "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f8a1ccebd0997e16112dfecfd74220b78e5b284b", - "reference": "f8a1ccebd0997e16112dfecfd74220b78e5b284b", + "url": "https://api.github.com/repos/symfony/string/zipball/73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", + "reference": "73a5e66ea2e1677c98d4449177c5a9cf9d8b4c6f", "shasum": "" }, "require": { @@ -6931,7 +7008,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.12" + "source": "https://github.com/symfony/string/tree/v6.4.15" }, "funding": [ { @@ -6947,20 +7024,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:15:52+00:00" + "time": "2024-11-13T13:31:12+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.5.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a" + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", - "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", "shasum": "" }, "require": { @@ -6968,12 +7045,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "3.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -7009,7 +7086,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0" + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" }, "funding": [ { @@ -7025,20 +7102,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:32:20+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/twig-bridge", - "version": "v6.4.12", + "version": "v6.4.17", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "09c0df13f822a1b80c5972ca1aa9eeb1288e1194" + "reference": "238e1aac992b5231c66faf10131ace7bdba97065" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/09c0df13f822a1b80c5972ca1aa9eeb1288e1194", - "reference": "09c0df13f822a1b80c5972ca1aa9eeb1288e1194", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/238e1aac992b5231c66faf10131ace7bdba97065", + "reference": "238e1aac992b5231c66faf10131ace7bdba97065", "shasum": "" }, "require": { @@ -7118,7 +7195,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.4.12" + "source": "https://github.com/symfony/twig-bridge/tree/v6.4.17" }, "funding": [ { @@ -7134,20 +7211,20 @@ "type": "tidelift" } ], - "time": "2024-09-15T06:35:36+00:00" + "time": "2024-12-19T14:08:41+00:00" }, { "name": "symfony/twig-bundle", - "version": "v6.4.12", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "4e63369647e3924e110b37337c6a58aac3086ad4" + "reference": "c3beeb5336aba1ea03c37e526968c2fde3ef25c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/4e63369647e3924e110b37337c6a58aac3086ad4", - "reference": "4e63369647e3924e110b37337c6a58aac3086ad4", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/c3beeb5336aba1ea03c37e526968c2fde3ef25c4", + "reference": "c3beeb5336aba1ea03c37e526968c2fde3ef25c4", "shasum": "" }, "require": { @@ -7202,7 +7279,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v6.4.12" + "source": "https://github.com/symfony/twig-bundle/tree/v6.4.13" }, "funding": [ { @@ -7218,20 +7295,20 @@ "type": "tidelift" } ], - "time": "2024-09-08T12:30:05+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/validator", - "version": "v6.4.12", + "version": "v6.4.17", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "6da1f0a1ee73d060a411d832cbe0539cfe9bbaa0" + "reference": "a3c19a0e542d427c207e22242043ef35b5b99a2c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/6da1f0a1ee73d060a411d832cbe0539cfe9bbaa0", - "reference": "6da1f0a1ee73d060a411d832cbe0539cfe9bbaa0", + "url": "https://api.github.com/repos/symfony/validator/zipball/a3c19a0e542d427c207e22242043ef35b5b99a2c", + "reference": "a3c19a0e542d427c207e22242043ef35b5b99a2c", "shasum": "" }, "require": { @@ -7299,7 +7376,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v6.4.12" + "source": "https://github.com/symfony/validator/tree/v6.4.17" }, "funding": [ { @@ -7315,20 +7392,20 @@ "type": "tidelift" } ], - "time": "2024-09-20T08:18:25+00:00" + "time": "2024-12-29T12:50:19+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.4.11", + "version": "v6.4.15", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "ee14c8254a480913268b1e3b1cba8045ed122694" + "reference": "38254d5a5ac2e61f2b52f9caf54e7aa3c9d36b80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/ee14c8254a480913268b1e3b1cba8045ed122694", - "reference": "ee14c8254a480913268b1e3b1cba8045ed122694", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/38254d5a5ac2e61f2b52f9caf54e7aa3c9d36b80", + "reference": "38254d5a5ac2e61f2b52f9caf54e7aa3c9d36b80", "shasum": "" }, "require": { @@ -7384,7 +7461,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.11" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.15" }, "funding": [ { @@ -7400,20 +7477,20 @@ "type": "tidelift" } ], - "time": "2024-08-30T16:03:21+00:00" + "time": "2024-11-08T15:28:48+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.4.9", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "f9a060622e0d93777b7f8687ec4860191e16802e" + "reference": "0f605f72a363f8743001038a176eeb2a11223b51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/f9a060622e0d93777b7f8687ec4860191e16802e", - "reference": "f9a060622e0d93777b7f8687ec4860191e16802e", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/0f605f72a363f8743001038a176eeb2a11223b51", + "reference": "0f605f72a363f8743001038a176eeb2a11223b51", "shasum": "" }, "require": { @@ -7461,7 +7538,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.9" + "source": "https://github.com/symfony/var-exporter/tree/v6.4.13" }, "funding": [ { @@ -7477,20 +7554,20 @@ "type": "tidelift" } ], - "time": "2024-06-24T15:53:56+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/web-link", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/web-link.git", - "reference": "304c67cefe7128ea3957e9bb1ac6ce08a90a635b" + "reference": "4d188b64bb9a9c5e2e4d20c8d5fdce6bbbb32c94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-link/zipball/304c67cefe7128ea3957e9bb1ac6ce08a90a635b", - "reference": "304c67cefe7128ea3957e9bb1ac6ce08a90a635b", + "url": "https://api.github.com/repos/symfony/web-link/zipball/4d188b64bb9a9c5e2e4d20c8d5fdce6bbbb32c94", + "reference": "4d188b64bb9a9c5e2e4d20c8d5fdce6bbbb32c94", "shasum": "" }, "require": { @@ -7544,7 +7621,7 @@ "push" ], "support": { - "source": "https://github.com/symfony/web-link/tree/v6.4.8" + "source": "https://github.com/symfony/web-link/tree/v6.4.13" }, "funding": [ { @@ -7560,20 +7637,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/yaml", - "version": "v6.4.12", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "762ee56b2649659380e0ef4d592d807bc17b7971" + "reference": "e99b4e94d124b29ee4cf3140e1b537d2dad8cec9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/762ee56b2649659380e0ef4d592d807bc17b7971", - "reference": "762ee56b2649659380e0ef4d592d807bc17b7971", + "url": "https://api.github.com/repos/symfony/yaml/zipball/e99b4e94d124b29ee4cf3140e1b537d2dad8cec9", + "reference": "e99b4e94d124b29ee4cf3140e1b537d2dad8cec9", "shasum": "" }, "require": { @@ -7616,7 +7693,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.12" + "source": "https://github.com/symfony/yaml/tree/v6.4.13" }, "funding": [ { @@ -7632,20 +7709,20 @@ "type": "tidelift" } ], - "time": "2024-09-17T12:47:12+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "twig/twig", - "version": "v3.14.0", + "version": "v3.18.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72" + "reference": "acffa88cc2b40dbe42eaf3a5025d6c0d4600cc50" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/126b2c97818dbff0cdf3fbfc881aedb3d40aae72", - "reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/acffa88cc2b40dbe42eaf3a5025d6c0d4600cc50", + "reference": "acffa88cc2b40dbe42eaf3a5025d6c0d4600cc50", "shasum": "" }, "require": { @@ -7656,6 +7733,7 @@ "symfony/polyfill-php81": "^1.29" }, "require-dev": { + "phpstan/phpstan": "^2.0", "psr/container": "^1.0|^2.0", "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, @@ -7699,7 +7777,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.14.0" + "source": "https://github.com/twigphp/Twig/tree/v3.18.0" }, "funding": [ { @@ -7711,7 +7789,7 @@ "type": "tidelift" } ], - "time": "2024-09-09T17:55:12+00:00" + "time": "2024-12-29T10:51:50+00:00" }, { "name": "webmozart/assert", @@ -7895,16 +7973,16 @@ }, { "name": "composer/pcre", - "version": "3.3.1", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4" + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/63aaeac21d7e775ff9bc9d45021e1745c97521c4", - "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", "shasum": "" }, "require": { @@ -7914,19 +7992,19 @@ "phpstan/phpstan": "<1.11.10" }, "require-dev": { - "phpstan/phpstan": "^1.11.10", - "phpstan/phpstan-strict-rules": "^1.1", + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", "phpunit/phpunit": "^8 || ^9" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - }, "phpstan": { "includes": [ "extension.neon" ] + }, + "branch-alias": { + "dev-main": "3.x-dev" } }, "autoload": { @@ -7954,7 +8032,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.3.1" + "source": "https://github.com/composer/pcre/tree/3.3.2" }, "funding": [ { @@ -7970,88 +8048,7 @@ "type": "tidelift" } ], - "time": "2024-08-27T18:44:43+00:00" - }, - { - "name": "composer/semver", - "version": "3.4.3", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", - "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.11", - "symfony/phpunit-bridge": "^3 || ^7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], - "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.3" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2024-09-19T14:15:21+00:00" + "time": "2024-11-12T16:29:46+00:00" }, { "name": "composer/xdebug-handler", @@ -8168,16 +8165,16 @@ }, { "name": "fakerphp/faker", - "version": "v1.23.1", + "version": "v1.24.1", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "bfb4fe148adbf78eff521199619b93a52ae3554b" + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/bfb4fe148adbf78eff521199619b93a52ae3554b", - "reference": "bfb4fe148adbf78eff521199619b93a52ae3554b", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", "shasum": "" }, "require": { @@ -8225,9 +8222,9 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v1.23.1" + "source": "https://github.com/FakerPHP/Faker/tree/v1.24.1" }, - "time": "2024-01-02T13:46:09+00:00" + "time": "2024-11-21T13:46:39+00:00" }, { "name": "fidry/cpu-core-counter", @@ -8462,16 +8459,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.12.0", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" + "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845", + "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845", "shasum": "" }, "require": { @@ -8510,7 +8507,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1" }, "funding": [ { @@ -8518,7 +8515,7 @@ "type": "tidelift" } ], - "time": "2024-06-12T14:39:25+00:00" + "time": "2024-11-08T17:47:46+00:00" }, { "name": "phar-io/manifest", @@ -8959,16 +8956,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.21", + "version": "9.6.22", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa" + "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", - "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c", + "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c", "shasum": "" }, "require": { @@ -8979,7 +8976,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.0", + "myclabs/deep-copy": "^1.12.1", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", @@ -9042,7 +9039,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.22" }, "funding": [ { @@ -9058,7 +9055,7 @@ "type": "tidelift" } ], - "time": "2024-09-19T10:50:18+00:00" + "time": "2024-12-05T13:48:26+00:00" }, { "name": "react/cache", @@ -9134,33 +9131,33 @@ }, { "name": "react/child-process", - "version": "v0.6.5", + "version": "v0.6.6", "source": { "type": "git", "url": "https://github.com/reactphp/child-process.git", - "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43" + "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/child-process/zipball/e71eb1aa55f057c7a4a0d08d06b0b0a484bead43", - "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43", + "url": "https://api.github.com/repos/reactphp/child-process/zipball/1721e2b93d89b745664353b9cfc8f155ba8a6159", + "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159", "shasum": "" }, "require": { "evenement/evenement": "^3.0 || ^2.0 || ^1.0", "php": ">=5.3.0", "react/event-loop": "^1.2", - "react/stream": "^1.2" + "react/stream": "^1.4" }, "require-dev": { - "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35", - "react/socket": "^1.8", + "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" + "React\\ChildProcess\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -9197,19 +9194,15 @@ ], "support": { "issues": "https://github.com/reactphp/child-process/issues", - "source": "https://github.com/reactphp/child-process/tree/v0.6.5" + "source": "https://github.com/reactphp/child-process/tree/v0.6.6" }, "funding": [ { - "url": "https://github.com/WyriHaximus", - "type": "github" - }, - { - "url": "https://github.com/clue", - "type": "github" + "url": "https://opencollective.com/reactphp", + "type": "open_collective" } ], - "time": "2022-09-16T13:41:56+00:00" + "time": "2025-01-01T16:37:48+00:00" }, { "name": "react/dns", @@ -10555,16 +10548,16 @@ }, { "name": "symfony/browser-kit", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "62ab90b92066ef6cce5e79365625b4b1432464c8" + "reference": "65d4b3fd9556e4b5b41287bef93c671f8f9f86ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/62ab90b92066ef6cce5e79365625b4b1432464c8", - "reference": "62ab90b92066ef6cce5e79365625b4b1432464c8", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/65d4b3fd9556e4b5b41287bef93c671f8f9f86ab", + "reference": "65d4b3fd9556e4b5b41287bef93c671f8f9f86ab", "shasum": "" }, "require": { @@ -10603,7 +10596,7 @@ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/browser-kit/tree/v6.4.8" + "source": "https://github.com/symfony/browser-kit/tree/v6.4.13" }, "funding": [ { @@ -10619,20 +10612,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "symfony/css-selector", - "version": "v6.4.8", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08" + "reference": "cb23e97813c5837a041b73a6d63a9ddff0778f5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/4b61b02fe15db48e3687ce1c45ea385d1780fe08", - "reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/cb23e97813c5837a041b73a6d63a9ddff0778f5e", + "reference": "cb23e97813c5837a041b73a6d63a9ddff0778f5e", "shasum": "" }, "require": { @@ -10668,7 +10661,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v6.4.8" + "source": "https://github.com/symfony/css-selector/tree/v6.4.13" }, "funding": [ { @@ -10684,20 +10677,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/dom-crawler", - "version": "v6.4.12", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "9d307ecbcb917001692be333cdc58f474fdb37f0" + "reference": "4304e6ad5c894a9c72831ad459f627bfd35d766d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/9d307ecbcb917001692be333cdc58f474fdb37f0", - "reference": "9d307ecbcb917001692be333cdc58f474fdb37f0", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4304e6ad5c894a9c72831ad459f627bfd35d766d", + "reference": "4304e6ad5c894a9c72831ad459f627bfd35d766d", "shasum": "" }, "require": { @@ -10735,7 +10728,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v6.4.12" + "source": "https://github.com/symfony/dom-crawler/tree/v6.4.16" }, "funding": [ { @@ -10751,20 +10744,20 @@ "type": "tidelift" } ], - "time": "2024-09-15T06:35:36+00:00" + "time": "2024-11-13T15:06:22+00:00" }, { "name": "symfony/maker-bundle", - "version": "v1.61.0", + "version": "v1.62.1", "source": { "type": "git", "url": "https://github.com/symfony/maker-bundle.git", - "reference": "a3b7f14d349f8f44ed752d4dde2263f77510cc18" + "reference": "468ff2708200c95ebc0d85d3174b6c6711b8a590" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/a3b7f14d349f8f44ed752d4dde2263f77510cc18", - "reference": "a3b7f14d349f8f44ed752d4dde2263f77510cc18", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/468ff2708200c95ebc0d85d3174b6c6711b8a590", + "reference": "468ff2708200c95ebc0d85d3174b6c6711b8a590", "shasum": "" }, "require": { @@ -10827,7 +10820,7 @@ ], "support": { "issues": "https://github.com/symfony/maker-bundle/issues", - "source": "https://github.com/symfony/maker-bundle/tree/v1.61.0" + "source": "https://github.com/symfony/maker-bundle/tree/v1.62.1" }, "funding": [ { @@ -10843,20 +10836,20 @@ "type": "tidelift" } ], - "time": "2024-08-29T22:50:23+00:00" + "time": "2025-01-15T00:21:40+00:00" }, { "name": "symfony/options-resolver", - "version": "v6.4.8", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "22ab9e9101ab18de37839074f8a1197f55590c1b" + "reference": "368128ad168f20e22c32159b9f761e456cec0c78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/22ab9e9101ab18de37839074f8a1197f55590c1b", - "reference": "22ab9e9101ab18de37839074f8a1197f55590c1b", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/368128ad168f20e22c32159b9f761e456cec0c78", + "reference": "368128ad168f20e22c32159b9f761e456cec0c78", "shasum": "" }, "require": { @@ -10894,7 +10887,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.4.8" + "source": "https://github.com/symfony/options-resolver/tree/v6.4.16" }, "funding": [ { @@ -10910,20 +10903,20 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:49:08+00:00" + "time": "2024-11-20T10:57:02+00:00" }, { "name": "symfony/phpunit-bridge", - "version": "v7.1.4", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "e876eb90e32a8fc4c4911d458e09f88d65877d1c" + "reference": "2bbde92ab25a0e2c88160857af7be9db5da0d145" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/e876eb90e32a8fc4c4911d458e09f88d65877d1c", - "reference": "e876eb90e32a8fc4c4911d458e09f88d65877d1c", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/2bbde92ab25a0e2c88160857af7be9db5da0d145", + "reference": "2bbde92ab25a0e2c88160857af7be9db5da0d145", "shasum": "" }, "require": { @@ -10943,8 +10936,8 @@ "type": "symfony-bridge", "extra": { "thanks": { - "name": "phpunit/phpunit", - "url": "https://github.com/sebastianbergmann/phpunit" + "url": "https://github.com/sebastianbergmann/phpunit", + "name": "phpunit/phpunit" } }, "autoload": { @@ -10976,7 +10969,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v7.1.4" + "source": "https://github.com/symfony/phpunit-bridge/tree/v7.2.0" }, "funding": [ { @@ -10992,20 +10985,20 @@ "type": "tidelift" } ], - "time": "2024-08-13T14:28:19+00:00" + "time": "2024-11-13T16:15:23+00:00" }, { "name": "symfony/process", - "version": "v6.4.12", + "version": "v6.4.15", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "3f94e5f13ff58df371a7ead461b6e8068900fbb3" + "reference": "3cb242f059c14ae08591c5c4087d1fe443564392" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/3f94e5f13ff58df371a7ead461b6e8068900fbb3", - "reference": "3f94e5f13ff58df371a7ead461b6e8068900fbb3", + "url": "https://api.github.com/repos/symfony/process/zipball/3cb242f059c14ae08591c5c4087d1fe443564392", + "reference": "3cb242f059c14ae08591c5c4087d1fe443564392", "shasum": "" }, "require": { @@ -11037,7 +11030,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.12" + "source": "https://github.com/symfony/process/tree/v6.4.15" }, "funding": [ { @@ -11053,7 +11046,7 @@ "type": "tidelift" } ], - "time": "2024-09-17T12:47:12+00:00" + "time": "2024-11-06T14:19:14+00:00" }, { "name": "theseer/tokenizer", @@ -11107,16 +11100,16 @@ }, { "name": "zenstruck/assert", - "version": "v1.5.0", + "version": "v1.5.1", "source": { "type": "git", "url": "https://github.com/zenstruck/assert.git", - "reference": "60956bb6584a51c6c2ab9fa8707b7c013d770163" + "reference": "39554ce3a275fbf8c870b251e620101f644e9277" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zenstruck/assert/zipball/60956bb6584a51c6c2ab9fa8707b7c013d770163", - "reference": "60956bb6584a51c6c2ab9fa8707b7c013d770163", + "url": "https://api.github.com/repos/zenstruck/assert/zipball/39554ce3a275fbf8c870b251e620101f644e9277", + "reference": "39554ce3a275fbf8c870b251e620101f644e9277", "shasum": "" }, "require": { @@ -11126,8 +11119,8 @@ }, "require-dev": { "phpstan/phpstan": "^1.4", - "phpunit/phpunit": "^9.5", - "symfony/phpunit-bridge": "^6.3" + "phpunit/phpunit": "^9.5.21", + "symfony/phpunit-bridge": "^6.3|^7.0" }, "type": "library", "autoload": { @@ -11154,7 +11147,7 @@ ], "support": { "issues": "https://github.com/zenstruck/assert/issues", - "source": "https://github.com/zenstruck/assert/tree/v1.5.0" + "source": "https://github.com/zenstruck/assert/tree/v1.5.1" }, "funding": [ { @@ -11162,7 +11155,7 @@ "type": "github" } ], - "time": "2023-12-02T09:08:04+00:00" + "time": "2024-10-28T18:08:12+00:00" }, { "name": "zenstruck/callback", @@ -11222,16 +11215,16 @@ }, { "name": "zenstruck/foundry", - "version": "v1.38.3", + "version": "v1.38.4", "source": { "type": "git", "url": "https://github.com/zenstruck/foundry.git", - "reference": "112e3a6ce1d75627a3fbfd6cd009055994167edb" + "reference": "dfc44dc51059f97a645f1858bd4db5b00bb7ebb3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zenstruck/foundry/zipball/112e3a6ce1d75627a3fbfd6cd009055994167edb", - "reference": "112e3a6ce1d75627a3fbfd6cd009055994167edb", + "url": "https://api.github.com/repos/zenstruck/foundry/zipball/dfc44dc51059f97a645f1858bd4db5b00bb7ebb3", + "reference": "dfc44dc51059f97a645f1858bd4db5b00bb7ebb3", "shasum": "" }, "require": { @@ -11266,9 +11259,9 @@ "type": "library", "extra": { "bamarni-bin": { - "target-directory": "bin/tools", "bin-links": true, - "forward-command": false + "forward-command": false, + "target-directory": "bin/tools" } }, "autoload": { @@ -11304,7 +11297,7 @@ ], "support": { "issues": "https://github.com/zenstruck/foundry/issues", - "source": "https://github.com/zenstruck/foundry/tree/v1.38.3" + "source": "https://github.com/zenstruck/foundry/tree/v1.38.4" }, "funding": [ { @@ -11312,7 +11305,7 @@ "type": "github" } ], - "time": "2024-07-04T19:59:49+00:00" + "time": "2025-01-03T09:04:39+00:00" } ], "aliases": [], From d922d1e0a08d5736750501fdbea1076340363a4c Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 12:49:13 +0100 Subject: [PATCH 63/76] Updated zenstruck/foundry to ^2.3 --- composer.json | 2 +- composer.lock | 125 ++++++++----------------- config/bundles.php | 2 +- config/packages/zenstruck_foundry.yaml | 2 - symfony.lock | 6 +- 5 files changed, 44 insertions(+), 93 deletions(-) diff --git a/composer.json b/composer.json index 393466d..5bf1627 100644 --- a/composer.json +++ b/composer.json @@ -97,6 +97,6 @@ "symfony/css-selector": "6.4.*", "symfony/maker-bundle": "^1.51", "symfony/phpunit-bridge": "^7.0", - "zenstruck/foundry": "^1.36" + "zenstruck/foundry": "^2.3" } } diff --git a/composer.lock b/composer.lock index 8824b6e..943a8cb 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": "606fea65b8befe4e0c0a4698dd4b24d7", + "content-hash": "6cc226fe79d183a514dbc0ba3f7c8e17", "packages": [ { "name": "api-platform/core", @@ -11157,107 +11157,55 @@ ], "time": "2024-10-28T18:08:12+00:00" }, - { - "name": "zenstruck/callback", - "version": "v1.5.0", - "source": { - "type": "git", - "url": "https://github.com/zenstruck/callback.git", - "reference": "eed9a532fd8974368e60c4a2550ed65eab7e5432" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zenstruck/callback/zipball/eed9a532fd8974368e60c4a2550ed65eab7e5432", - "reference": "eed9a532fd8974368e60c4a2550ed65eab7e5432", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.14" - }, - "require-dev": { - "symfony/phpunit-bridge": "^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "Zenstruck\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kevin Bond", - "email": "kevinbond@gmail.com" - } - ], - "description": "Callable wrapper to validate and inject arguments.", - "homepage": "https://github.com/zenstruck/callback", - "keywords": [ - "callable", - "callback", - "utility" - ], - "support": { - "issues": "https://github.com/zenstruck/callback/issues", - "source": "https://github.com/zenstruck/callback/tree/v1.5.0" - }, - "funding": [ - { - "url": "https://github.com/kbond", - "type": "github" - } - ], - "time": "2022-08-31T14:56:15+00:00" - }, { "name": "zenstruck/foundry", - "version": "v1.38.4", + "version": "v2.3.1", "source": { "type": "git", "url": "https://github.com/zenstruck/foundry.git", - "reference": "dfc44dc51059f97a645f1858bd4db5b00bb7ebb3" + "reference": "6f744b05706c1780e61368f23bf77e18c83d8fcd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zenstruck/foundry/zipball/dfc44dc51059f97a645f1858bd4db5b00bb7ebb3", - "reference": "dfc44dc51059f97a645f1858bd4db5b00bb7ebb3", + "url": "https://api.github.com/repos/zenstruck/foundry/zipball/6f744b05706c1780e61368f23bf77e18c83d8fcd", + "reference": "6f744b05706c1780e61368f23bf77e18c83d8fcd", "shasum": "" }, "require": { - "doctrine/persistence": "^1.3.3|^2.0|^3.0", - "fakerphp/faker": "^1.10", - "php": ">=8.0", + "doctrine/persistence": "^2.0|^3.0", + "fakerphp/faker": "^1.23", + "php": ">=8.1", "symfony/deprecation-contracts": "^2.2|^3.0", - "symfony/property-access": "^5.4|^6.0|^7.0", - "symfony/string": "^5.4|^6.0|^7.0", - "zenstruck/assert": "^1.0", - "zenstruck/callback": "^1.1" - }, - "conflict": { - "doctrine/mongodb-odm": "2.5.0" + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/var-exporter": "^6.4.9|~7.0.9|^7.1.2", + "zenstruck/assert": "^1.4" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8", + "brianium/paratest": "^6|^7", "dama/doctrine-test-bundle": "^7.0|^8.0", - "doctrine/doctrine-bundle": "^2.5", + "doctrine/collections": "^1.7|^2.0", + "doctrine/common": "^3.2", + "doctrine/doctrine-bundle": "^2.10", "doctrine/doctrine-migrations-bundle": "^2.2|^3.0", - "doctrine/mongodb-odm": "^2.4", - "doctrine/mongodb-odm-bundle": "^4.4.0|^5.0", - "doctrine/orm": "^2.11|^3.0", - "matthiasnoback/symfony-dependency-injection-test": "^4.1|^5.0", - "phpunit/phpunit": "^9.5.0", - "symfony/dotenv": "^5.4|^6.0|^7.0", - "symfony/framework-bundle": "^5.4|^6.0|^7.0", - "symfony/maker-bundle": "^1.49", - "symfony/phpunit-bridge": "^5.4|^6.0|^7.0", - "symfony/translation-contracts": "^2.5|^3.0" + "doctrine/mongodb-odm-bundle": "^4.6|^5.0", + "doctrine/orm": "^2.16|^3.0", + "phpunit/phpunit": "^9.5.0 || ^10.0 || ^11.0", + "symfony/console": "^6.4|^7.0", + "symfony/dotenv": "^6.4|^7.0", + "symfony/maker-bundle": "^1.55", + "symfony/phpunit-bridge": "^6.4|^7.0", + "symfony/runtime": "^6.4|^7.0", + "symfony/translation-contracts": "^3.4", + "symfony/var-dumper": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" }, "type": "library", "extra": { + "psalm": { + "pluginClass": "Zenstruck\\Foundry\\Psalm\\FoundryPlugin" + }, "bamarni-bin": { "bin-links": true, "forward-command": false, @@ -11267,11 +11215,12 @@ "autoload": { "files": [ "src/functions.php", - "src/Persistence/functions.php" + "src/Persistence/functions.php", + "src/symfony_console.php" ], "psr-4": { "Zenstruck\\Foundry\\": "src/", - "Zenstruck\\Foundry\\Utils\\Rector\\": "utils/rector/src/" + "Zenstruck\\Foundry\\Psalm\\": "utils/psalm" } }, "notification-url": "https://packagist.org/downloads/", @@ -11282,6 +11231,10 @@ { "name": "Kevin Bond", "email": "kevinbond@gmail.com" + }, + { + "name": "Nicolas PHILIPPE", + "email": "nikophil@gmail.com" } ], "description": "A model factory library for creating expressive, auto-completable, on-demand dev/test fixtures with Symfony and Doctrine.", @@ -11297,7 +11250,7 @@ ], "support": { "issues": "https://github.com/zenstruck/foundry/issues", - "source": "https://github.com/zenstruck/foundry/tree/v1.38.4" + "source": "https://github.com/zenstruck/foundry/tree/v2.3.1" }, "funding": [ { @@ -11305,7 +11258,7 @@ "type": "github" } ], - "time": "2025-01-03T09:04:39+00:00" + "time": "2024-12-12T09:03:06+00:00" } ], "aliases": [], diff --git a/config/bundles.php b/config/bundles.php index 9dbe7c2..0def149 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -7,11 +7,11 @@ return [ Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true], ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true], Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], - Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true], Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], Ambta\DoctrineEncryptBundle\AmbtaDoctrineEncryptBundle::class => ['all' => true], AutoMapper\Symfony\Bundle\AutoMapperBundle::class => ['all' => true], + Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['dev' => true, 'test' => true], ]; diff --git a/config/packages/zenstruck_foundry.yaml b/config/packages/zenstruck_foundry.yaml index 0657d2c..e3ed04b 100644 --- a/config/packages/zenstruck_foundry.yaml +++ b/config/packages/zenstruck_foundry.yaml @@ -1,7 +1,5 @@ when@dev: &dev # See full configuration: https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#full-default-bundle-configuration zenstruck_foundry: - # Whether to auto-refresh proxies by default (https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#auto-refresh) - auto_refresh_proxies: true when@test: *dev diff --git a/symfony.lock b/symfony.lock index 28dbadb..e21d55d 100644 --- a/symfony.lock +++ b/symfony.lock @@ -244,12 +244,12 @@ ] }, "zenstruck/foundry": { - "version": "1.36", + "version": "2.3", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "1.10", - "ref": "37c2f894cc098ab4c08874b80cccc8e2f8de7976" + "version": "2.0", + "ref": "56bc588a1b6d5d218319f70c64c2f0fbebe30ec7" }, "files": [ "config/packages/zenstruck_foundry.yaml" From bce42bd452f7570ecba71ff7146813eebd28f64b Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 13:19:53 +0100 Subject: [PATCH 64/76] Upgrade to api-platform 4 --- composer.json | 3 +- composer.lock | 1438 +++++++++++++++++++++++++---- config/packages/api_platform.yaml | 4 +- config/packages/uid.yaml | 4 + symfony.lock | 26 + 5 files changed, 1308 insertions(+), 167 deletions(-) create mode 100644 config/packages/uid.yaml diff --git a/composer.json b/composer.json index 5bf1627..1d70080 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,8 @@ "php": ">=8.1", "ext-ctype": "*", "ext-iconv": "*", - "api-platform/core": "^3.2", + "api-platform/doctrine-orm": "^4.0", + "api-platform/symfony": "^4.0", "beberlei/doctrineextensions": "^1.4", "brick/math": "^0.11.0", "brick/money": "^0.8.1", diff --git a/composer.lock b/composer.lock index 943a8cb..124bb9d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,188 +4,55 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6cc226fe79d183a514dbc0ba3f7c8e17", + "content-hash": "6b7778236794d7ea905247c502a8189d", "packages": [ { - "name": "api-platform/core", - "version": "v3.4.15", + "name": "api-platform/doctrine-common", + "version": "v4.0.15", "source": { "type": "git", - "url": "https://github.com/api-platform/core.git", - "reference": "2055e08bca997a2707d7a3252c939953101de9c8" + "url": "https://github.com/api-platform/doctrine-common.git", + "reference": "eb82d8531ed9a4b59ea0028f3429c464d0530bc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/api-platform/core/zipball/2055e08bca997a2707d7a3252c939953101de9c8", - "reference": "2055e08bca997a2707d7a3252c939953101de9c8", + "url": "https://api.github.com/repos/api-platform/doctrine-common/zipball/eb82d8531ed9a4b59ea0028f3429c464d0530bc4", + "reference": "eb82d8531ed9a4b59ea0028f3429c464d0530bc4", "shasum": "" }, "require": { - "doctrine/inflector": "^1.0 || ^2.0", - "php": ">=8.1", - "psr/cache": "^1.0 || ^2.0 || ^3.0", - "psr/container": "^1.0 || ^2.0", - "symfony/deprecation-contracts": "^3.1", - "symfony/http-foundation": "^6.4 || ^7.1", - "symfony/http-kernel": "^6.4 || ^7.1", - "symfony/property-access": "^6.4 || ^7.1", - "symfony/property-info": "^6.4 || ^7.1", - "symfony/serializer": "^6.4 || ^7.1", - "symfony/translation-contracts": "^3.3", - "symfony/web-link": "^6.4 || ^7.1", - "willdurand/negotiation": "^3.0" + "api-platform/metadata": "^3.4 || ^4.0", + "api-platform/state": "^3.4 || ^4.0", + "doctrine/collections": "^2.1", + "doctrine/common": "^3.2.2", + "doctrine/persistence": "^3.2", + "php": ">=8.2" }, "conflict": { - "doctrine/common": "<3.2.2", - "doctrine/dbal": "<2.10", - "doctrine/mongodb-odm": "<2.4", - "doctrine/orm": "<2.14.0", - "doctrine/persistence": "<1.3", - "elasticsearch/elasticsearch": ">=8.0,<8.4", - "phpspec/prophecy": "<1.15", - "phpunit/phpunit": "<9.5", - "symfony/framework-bundle": "6.4.6 || 7.0.6", - "symfony/var-exporter": "<6.1.1" - }, - "replace": { - "api-platform/doctrine-common": "self.version", - "api-platform/doctrine-odm": "self.version", - "api-platform/doctrine-orm": "self.version", - "api-platform/documentation": "self.version", - "api-platform/elasticsearch": "self.version", - "api-platform/graphql": "self.version", - "api-platform/http-cache": "self.version", - "api-platform/hydra": "self.version", - "api-platform/json-api": "self.version", - "api-platform/json-hal": "self.version", - "api-platform/json-schema": "self.version", - "api-platform/jsonld": "self.version", - "api-platform/laravel": "self.version", - "api-platform/metadata": "self.version", - "api-platform/openapi": "self.version", - "api-platform/parameter-validator": "self.version", - "api-platform/ramsey-uuid": "self.version", - "api-platform/serializer": "self.version", - "api-platform/state": "self.version", - "api-platform/symfony": "self.version", - "api-platform/validator": "self.version" + "doctrine/persistence": "<1.3" }, "require-dev": { - "api-platform/doctrine-common": "^3.4 || ^4.0", - "api-platform/doctrine-odm": "^3.4 || ^4.0", - "api-platform/doctrine-orm": "^3.4 || ^4.0", - "api-platform/documentation": "^3.4 || ^4.0", - "api-platform/elasticsearch": "^3.4 || ^4.0", - "api-platform/graphql": "^3.4 || ^4.0", - "api-platform/http-cache": "^3.4 || ^4.0", - "api-platform/hydra": "^3.4 || ^4.0", - "api-platform/json-api": "^3.3 || ^4.0", - "api-platform/json-schema": "^3.4 || ^4.0", - "api-platform/jsonld": "^3.4 || ^4.0", - "api-platform/metadata": "^3.4 || ^4.0", - "api-platform/openapi": "^3.4 || ^4.0", - "api-platform/parameter-validator": "^3.4", - "api-platform/ramsey-uuid": "^3.4 || ^4.0", - "api-platform/serializer": "^3.4 || ^4.0", - "api-platform/state": "^3.4 || ^4.0", - "api-platform/validator": "^3.4 || ^4.0", - "behat/behat": "^3.11", - "behat/mink": "^1.9", - "doctrine/cache": "^1.11 || ^2.1", - "doctrine/common": "^3.2.2", - "doctrine/dbal": "^3.4.0 || ^4.0", - "doctrine/doctrine-bundle": "^1.12 || ^2.0", - "doctrine/mongodb-odm": "^2.2", - "doctrine/mongodb-odm-bundle": "^4.0 || ^5.0", - "doctrine/orm": "^2.14 || ^3.0", - "elasticsearch/elasticsearch": "^7.11 || ^8.4", - "friends-of-behat/mink-browserkit-driver": "^1.3.1", - "friends-of-behat/mink-extension": "^2.2", - "friends-of-behat/symfony-extension": "^2.1", - "guzzlehttp/guzzle": "^6.0 || ^7.1", - "jangregor/phpstan-prophecy": "^1.0", - "justinrainbow/json-schema": "^5.2.1", - "phpspec/prophecy-phpunit": "^2.0", - "phpstan/extension-installer": "^1.1", - "phpstan/phpdoc-parser": "^1.13|^2.0", - "phpstan/phpstan": "^1.10", - "phpstan/phpstan-doctrine": "^1.0", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-symfony": "^1.0", - "phpunit/phpunit": "^9.6", - "psr/log": "^1.0 || ^2.0 || ^3.0", - "ramsey/uuid": "^3.9.7 || ^4.0", - "ramsey/uuid-doctrine": "^1.4 || ^2.0 || ^3.0", - "sebastian/comparator": "<5.0", - "soyuka/contexts": "v3.3.9", - "soyuka/pmu": "^0.0.12", - "soyuka/stubs-mongodb": "^1.0", - "symfony/asset": "^6.4 || ^7.1", - "symfony/browser-kit": "^6.4 || ^7.1", - "symfony/cache": "^6.4 || ^7.1", - "symfony/config": "^6.4 || ^7.1", - "symfony/console": "^6.4 || ^7.1", - "symfony/css-selector": "^6.4 || ^7.1", - "symfony/dependency-injection": "^6.4 || ^7.1", - "symfony/doctrine-bridge": "^6.4 || ^7.1", - "symfony/dom-crawler": "^6.4 || ^7.1", - "symfony/error-handler": "^6.4 || ^7.1", - "symfony/event-dispatcher": "^6.4 || ^7.1", - "symfony/expression-language": "^6.4 || ^7.1", - "symfony/finder": "^6.4 || ^7.1", - "symfony/form": "^6.4 || ^7.1", - "symfony/framework-bundle": "^6.4 || ^7.1", - "symfony/http-client": "^6.4 || ^7.1", - "symfony/intl": "^6.4 || ^7.1", - "symfony/maker-bundle": "^1.24", - "symfony/mercure-bundle": "*", - "symfony/messenger": "^6.4 || ^7.1", - "symfony/phpunit-bridge": "^6.4.1 || ^7.1", - "symfony/routing": "^6.4 || ^7.1", - "symfony/security-bundle": "^6.4 || ^7.1", - "symfony/security-core": "^6.4 || ^7.1", - "symfony/stopwatch": "^6.4 || ^7.1", - "symfony/string": "^6.4 || ^7.1", - "symfony/twig-bundle": "^6.4 || ^7.1", - "symfony/uid": "^6.4 || ^7.1", - "symfony/validator": "^6.4 || ^7.1", - "symfony/web-profiler-bundle": "^6.4 || ^7.1", - "symfony/yaml": "^6.4 || ^7.1", - "twig/twig": "^1.42.3 || ^2.12 || ^3.0", - "webonyx/graphql-php": "^14.0 || ^15.0" + "doctrine/mongodb-odm": "^2.6", + "doctrine/orm": "^2.17 || ^3.0", + "phpspec/prophecy-phpunit": "^2.2", + "phpunit/phpunit": "^11.2" }, "suggest": { - "doctrine/mongodb-odm-bundle": "To support MongoDB. Only versions 4.0 and later are supported.", - "elasticsearch/elasticsearch": "To support Elasticsearch.", - "ocramius/package-versions": "To display the API Platform's version in the debug bar.", - "phpstan/phpdoc-parser": "To support extracting metadata from PHPDoc.", - "psr/cache-implementation": "To use metadata caching.", - "ramsey/uuid": "To support Ramsey's UUID identifiers.", - "symfony/cache": "To have metadata caching when using Symfony integration.", - "symfony/config": "To load XML configuration files.", - "symfony/expression-language": "To use authorization features.", - "symfony/http-client": "To use the HTTP cache invalidation system.", - "symfony/messenger": "To support messenger integration.", - "symfony/security": "To use authorization features.", - "symfony/twig-bundle": "To use the Swagger UI integration.", - "symfony/uid": "To support Symfony UUID/ULID identifiers.", - "symfony/web-profiler-bundle": "To use the data collector.", - "webonyx/graphql-php": "To support GraphQL." + "api-platform/graphql": "For GraphQl mercure subscriptions.", + "api-platform/http-cache": "For HTTP cache invalidation.", + "phpstan/phpdoc-parser": "For PHP documentation support.", + "symfony/config": "For XML resource configuration.", + "symfony/mercure-bundle": "For mercure updates publisher.", + "symfony/yaml": "For YAML resource configuration." }, "type": "library", "extra": { - "pmu": { - "projects": [ - "./src/*/composer.json", - "src/Doctrine/*/composer.json" - ] - }, "thanks": { "url": "https://github.com/api-platform/api-platform", "name": "api-platform/api-platform" }, "symfony": { - "require": "^6.4 || ^7.1" + "require": "^6.4 || ^7.0" }, "branch-alias": { "dev-3.4": "3.4.x-dev", @@ -194,7 +61,7 @@ }, "autoload": { "psr-4": { - "ApiPlatform\\": "src/" + "ApiPlatform\\Doctrine\\Common\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -206,9 +73,566 @@ "name": "Kévin Dunglas", "email": "kevin@dunglas.fr", "homepage": "https://dunglas.fr" + }, + { + "name": "API Platform Community", + "homepage": "https://api-platform.com/community/contributors" } ], - "description": "Build a fully-featured hypermedia or GraphQL API in minutes!", + "description": "Common files used by api-platform/doctrine-orm and api-platform/doctrine-odm", + "homepage": "https://api-platform.com", + "keywords": [ + "doctrine", + "graphql", + "odm", + "orm", + "rest" + ], + "support": { + "source": "https://github.com/api-platform/doctrine-common/tree/v4.0.15" + }, + "time": "2024-09-21T11:01:16+00:00" + }, + { + "name": "api-platform/doctrine-orm", + "version": "v4.0.15", + "source": { + "type": "git", + "url": "https://github.com/api-platform/doctrine-orm.git", + "reference": "b7c1b0aa7c3fa0c43ce068e52a6ca3256ca8aa3a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/api-platform/doctrine-orm/zipball/b7c1b0aa7c3fa0c43ce068e52a6ca3256ca8aa3a", + "reference": "b7c1b0aa7c3fa0c43ce068e52a6ca3256ca8aa3a", + "shasum": "" + }, + "require": { + "api-platform/doctrine-common": "^3.4 || ^4.0", + "api-platform/metadata": "^3.4 || ^4.0", + "api-platform/state": "^3.4 || ^4.0", + "doctrine/orm": "^2.17 || ^3.0", + "php": ">=8.2", + "symfony/property-info": "^6.4 || ^7.0" + }, + "require-dev": { + "doctrine/doctrine-bundle": "^2.11", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^10.0", + "ramsey/uuid": "^4.7", + "ramsey/uuid-doctrine": "^2.0", + "symfony/cache": "^6.4 || ^7.0", + "symfony/framework-bundle": "^6.4 || ^7.0", + "symfony/property-access": "^6.4 || ^7.0", + "symfony/serializer": "^6.4 || ^7.0", + "symfony/uid": "^6.4 || ^7.0", + "symfony/validator": "^6.4 || ^7.0", + "symfony/yaml": "^6.4 || ^7.0" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.0" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "ApiPlatform\\Doctrine\\Orm\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr", + "homepage": "https://dunglas.fr" + }, + { + "name": "API Platform Community", + "homepage": "https://api-platform.com/community/contributors" + } + ], + "description": "Doctrine ORM bridge", + "homepage": "https://api-platform.com", + "keywords": [ + "api", + "doctrine", + "graphql", + "orm", + "rest" + ], + "support": { + "source": "https://github.com/api-platform/doctrine-orm/tree/v4.0.15" + }, + "time": "2024-12-13T13:34:25+00:00" + }, + { + "name": "api-platform/documentation", + "version": "v4.0.15", + "source": { + "type": "git", + "url": "https://github.com/api-platform/documentation.git", + "reference": "e0fef856ccf0af34d7bcc8f789c521f9ace3fcf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/api-platform/documentation/zipball/e0fef856ccf0af34d7bcc8f789c521f9ace3fcf7", + "reference": "e0fef856ccf0af34d7bcc8f789c521f9ace3fcf7", + "shasum": "" + }, + "require": { + "api-platform/metadata": "^3.4 || ^4.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.2" + }, + "type": "project", + "extra": { + "thanks": { + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.0" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "ApiPlatform\\Documentation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr", + "homepage": "https://dunglas.fr" + }, + { + "name": "API Platform Community", + "homepage": "https://api-platform.com/community/contributors" + } + ], + "description": "API Platform documentation controller.", + "support": { + "source": "https://github.com/api-platform/documentation/tree/v4.1.0-alpha.1" + }, + "time": "2024-09-21T11:01:16+00:00" + }, + { + "name": "api-platform/http-cache", + "version": "v4.0.15", + "source": { + "type": "git", + "url": "https://github.com/api-platform/http-cache.git", + "reference": "b21433319d93e90ae7b1df098cd604dc8555b632" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/api-platform/http-cache/zipball/b21433319d93e90ae7b1df098cd604dc8555b632", + "reference": "b21433319d93e90ae7b1df098cd604dc8555b632", + "shasum": "" + }, + "require": { + "api-platform/metadata": "^3.4 || ^4.0", + "api-platform/state": "^3.4 || ^4.0", + "php": ">=8.2", + "symfony/http-foundation": "^6.4 || ^7.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^6.0 || ^7.0", + "phpspec/prophecy-phpunit": "^2.2", + "phpunit/phpunit": "^11.2", + "symfony/dependency-injection": "^6.4 || ^7.0", + "symfony/http-client": "^6.4 || ^7.0" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.0" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "ApiPlatform\\HttpCache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr", + "homepage": "https://dunglas.fr" + }, + { + "name": "API Platform Community", + "homepage": "https://api-platform.com/comunnity/contributors" + } + ], + "description": "API Platform HttpCache component", + "homepage": "https://api-platform.com", + "keywords": [ + "api", + "cache", + "http", + "rest" + ], + "support": { + "source": "https://github.com/api-platform/http-cache/tree/v4.1.0-alpha.1" + }, + "time": "2024-10-28T09:21:17+00:00" + }, + { + "name": "api-platform/hydra", + "version": "v4.0.15", + "source": { + "type": "git", + "url": "https://github.com/api-platform/hydra.git", + "reference": "cc9501891225d8cdfc00d7c877a50e70e858c6cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/api-platform/hydra/zipball/cc9501891225d8cdfc00d7c877a50e70e858c6cf", + "reference": "cc9501891225d8cdfc00d7c877a50e70e858c6cf", + "shasum": "" + }, + "require": { + "api-platform/documentation": "^3.4 || ^4.0", + "api-platform/json-schema": "^3.4 || ^4.0", + "api-platform/jsonld": "^3.4 || ^4.0", + "api-platform/metadata": "^3.4 || ^4.0", + "api-platform/serializer": "^3.4 || ^4.0", + "api-platform/state": "^3.4 || ^4.0", + "php": ">=8.2", + "symfony/web-link": "^6.4 || ^7.0" + }, + "require-dev": { + "api-platform/doctrine-common": "^3.4 || ^4.0", + "api-platform/doctrine-odm": "^3.4 || ^4.0", + "api-platform/doctrine-orm": "^3.4 || ^4.0", + "phpspec/prophecy": "^1.19", + "phpspec/prophecy-phpunit": "^2.2", + "phpunit/phpunit": "^11.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.0" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "ApiPlatform\\Hydra\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr", + "homepage": "https://dunglas.fr" + }, + { + "name": "API Platform Community", + "homepage": "https://api-platform.com/community/contributors" + } + ], + "description": "API Hydra support", + "homepage": "https://api-platform.com", + "keywords": [ + "Hydra", + "JSON-LD", + "api", + "graphql", + "jsonapi", + "rest" + ], + "support": { + "source": "https://github.com/api-platform/hydra/tree/v4.0.15" + }, + "time": "2024-11-06T10:50:57+00:00" + }, + { + "name": "api-platform/json-schema", + "version": "v4.0.15", + "source": { + "type": "git", + "url": "https://github.com/api-platform/json-schema.git", + "reference": "aa9a6774a1cc3b02b7713466d5809e024a019e5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/api-platform/json-schema/zipball/aa9a6774a1cc3b02b7713466d5809e024a019e5c", + "reference": "aa9a6774a1cc3b02b7713466d5809e024a019e5c", + "shasum": "" + }, + "require": { + "api-platform/metadata": "^3.4 || ^4.0", + "php": ">=8.2", + "symfony/console": "^6.4 || ^7.0", + "symfony/property-info": "^6.4 || ^7.0", + "symfony/serializer": "^6.4 || ^7.0", + "symfony/uid": "^6.4 || ^7.0" + }, + "require-dev": { + "phpspec/prophecy-phpunit": "^2.2", + "phpunit/phpunit": "^11.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.0" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "ApiPlatform\\JsonSchema\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr", + "homepage": "https://dunglas.fr" + }, + { + "name": "API Platform Community", + "homepage": "https://api-platform.com/community/contributors" + } + ], + "description": "Generate a JSON Schema from a PHP class", + "homepage": "https://api-platform.com", + "keywords": [ + "JSON Schema", + "api", + "json", + "openapi", + "rest", + "swagger" + ], + "support": { + "source": "https://github.com/api-platform/json-schema/tree/v4.0.15" + }, + "time": "2025-01-17T09:55:19+00:00" + }, + { + "name": "api-platform/jsonld", + "version": "v4.0.15", + "source": { + "type": "git", + "url": "https://github.com/api-platform/jsonld.git", + "reference": "f4123465689e3f853ea6ce9ca70265a78aa5603e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/api-platform/jsonld/zipball/f4123465689e3f853ea6ce9ca70265a78aa5603e", + "reference": "f4123465689e3f853ea6ce9ca70265a78aa5603e", + "shasum": "" + }, + "require": { + "api-platform/metadata": "^3.4 || ^4.0", + "api-platform/serializer": "^3.4 || ^4.0", + "api-platform/state": "^3.4 || ^4.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.0" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" + } + }, + "autoload": { + "files": [ + "./HydraContext.php" + ], + "psr-4": { + "ApiPlatform\\JsonLd\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr", + "homepage": "https://dunglas.fr" + }, + { + "name": "API Platform Community", + "homepage": "https://api-platform.com/community/contributors" + } + ], + "description": "API JSON-LD support", + "homepage": "https://api-platform.com", + "keywords": [ + "Hydra", + "JSON-LD", + "api", + "graphql", + "rest" + ], + "support": { + "source": "https://github.com/api-platform/jsonld/tree/v4.1.0-alpha.1" + }, + "time": "2024-12-19T16:01:35+00:00" + }, + { + "name": "api-platform/metadata", + "version": "v4.0.15", + "source": { + "type": "git", + "url": "https://github.com/api-platform/metadata.git", + "reference": "64676272f0b5ed41bde6844e7129f8e7e9862bd4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/api-platform/metadata/zipball/64676272f0b5ed41bde6844e7129f8e7e9862bd4", + "reference": "64676272f0b5ed41bde6844e7129f8e7e9862bd4", + "shasum": "" + }, + "require": { + "doctrine/inflector": "^1.0 || ^2.0", + "php": ">=8.2", + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/property-info": "^6.4 || ^7.0", + "symfony/string": "^6.4 || ^7.0", + "symfony/type-info": "^7.1" + }, + "require-dev": { + "api-platform/json-schema": "^3.4 || ^4.0", + "api-platform/openapi": "^3.4 || ^4.0", + "api-platform/state": "^3.4 || ^4.0", + "phpspec/prophecy-phpunit": "^2.2", + "phpstan/phpdoc-parser": "^1.13", + "phpunit/phpunit": "^11.2", + "symfony/config": "^6.4 || ^7.0", + "symfony/routing": "^6.4 || ^7.0", + "symfony/var-dumper": "^6.4 || ^7.0", + "symfony/web-link": "^6.4 || ^7.0", + "symfony/yaml": "^6.4 || ^7.0" + }, + "suggest": { + "phpstan/phpdoc-parser": "For PHP documentation support.", + "symfony/config": "For XML resource configuration.", + "symfony/yaml": "For YAML resource configuration." + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.0" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "ApiPlatform\\Metadata\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr", + "homepage": "https://dunglas.fr" + }, + { + "name": "API Platform Community", + "homepage": "https://api-platform.com/community/contributors" + } + ], + "description": "API Resource-oriented metadata attributes and factories", "homepage": "https://api-platform.com", "keywords": [ "Hydra", @@ -222,10 +646,470 @@ "swagger" ], "support": { - "issues": "https://github.com/api-platform/core/issues", - "source": "https://github.com/api-platform/core/tree/v3.4.15" + "source": "https://github.com/api-platform/metadata/tree/v4.0.15" }, - "time": "2025-01-17T09:51:46+00:00" + "time": "2025-01-10T14:24:27+00:00" + }, + { + "name": "api-platform/openapi", + "version": "v4.0.15", + "source": { + "type": "git", + "url": "https://github.com/api-platform/openapi.git", + "reference": "3145c45ad6e668e20beff2653c1f245296c33d1c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/api-platform/openapi/zipball/3145c45ad6e668e20beff2653c1f245296c33d1c", + "reference": "3145c45ad6e668e20beff2653c1f245296c33d1c", + "shasum": "" + }, + "require": { + "api-platform/json-schema": "^3.4 || ^4.0", + "api-platform/metadata": "^3.4 || ^4.0", + "api-platform/state": "^3.4 || ^4.0", + "php": ">=8.2", + "symfony/console": "^6.4 || ^7.0", + "symfony/property-access": "^6.4 || ^7.0", + "symfony/serializer": "^6.4 || ^7.0" + }, + "require-dev": { + "api-platform/doctrine-common": "^3.4 || ^4.0", + "api-platform/doctrine-odm": "^3.4 || ^4.0", + "api-platform/doctrine-orm": "^3.4 || ^4.0", + "phpspec/prophecy-phpunit": "^2.2", + "phpunit/phpunit": "^11.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.0" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "ApiPlatform\\OpenApi\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr", + "homepage": "https://dunglas.fr" + }, + { + "name": "API Platform Community", + "homepage": "https://api-platform.com/community/contributors" + } + ], + "description": "Models to build and serialize an OpenAPI specification.", + "homepage": "https://api-platform.com", + "keywords": [ + "Hydra", + "JSON-LD", + "api", + "graphql", + "hal", + "jsonapi", + "openapi", + "rest", + "swagger" + ], + "support": { + "source": "https://github.com/api-platform/openapi/tree/v4.0.15" + }, + "time": "2025-01-09T14:23:11+00:00" + }, + { + "name": "api-platform/serializer", + "version": "v4.0.15", + "source": { + "type": "git", + "url": "https://github.com/api-platform/serializer.git", + "reference": "ceebfcf062e9da65e0a0626d10644f844a4d67f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/api-platform/serializer/zipball/ceebfcf062e9da65e0a0626d10644f844a4d67f0", + "reference": "ceebfcf062e9da65e0a0626d10644f844a4d67f0", + "shasum": "" + }, + "require": { + "api-platform/metadata": "^3.4 || ^4.0", + "api-platform/state": "^3.4 || ^4.0", + "php": ">=8.2", + "symfony/property-access": "^6.4 || ^7.0", + "symfony/property-info": "^6.4 || ^7.0", + "symfony/serializer": "^6.4 || ^7.0", + "symfony/validator": "^6.4 || ^7.0" + }, + "require-dev": { + "api-platform/doctrine-common": "^3.4 || ^4.0", + "api-platform/doctrine-odm": "^3.4 || ^4.0", + "api-platform/doctrine-orm": "^3.4 || ^4.0", + "api-platform/json-schema": "^3.4 || ^4.0", + "api-platform/openapi": "^3.4 || ^4.0", + "doctrine/collections": "^2.1", + "phpspec/prophecy-phpunit": "^2.2", + "phpunit/phpunit": "^11.2", + "symfony/mercure-bundle": "*", + "symfony/var-dumper": "^6.4 || ^7.0", + "symfony/yaml": "^6.4 || ^7.0" + }, + "suggest": { + "api-platform/doctrine-odm": "To support Doctrine MongoDB ODM state options.", + "api-platform/doctrine-orm": "To support Doctrine ORM state options." + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.0" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "ApiPlatform\\Serializer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr", + "homepage": "https://dunglas.fr" + }, + { + "name": "API Platform Community", + "homepage": "https://api-platform.com/community/contributors" + } + ], + "description": "API Platform core Serializer", + "homepage": "https://api-platform.com", + "keywords": [ + "api", + "graphql", + "rest", + "serializer" + ], + "support": { + "source": "https://github.com/api-platform/serializer/tree/v4.1.0-alpha.1" + }, + "time": "2024-12-01T10:27:17+00:00" + }, + { + "name": "api-platform/state", + "version": "v4.0.15", + "source": { + "type": "git", + "url": "https://github.com/api-platform/state.git", + "reference": "07310ba69b1f402155a6d214835625325748d150" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/api-platform/state/zipball/07310ba69b1f402155a6d214835625325748d150", + "reference": "07310ba69b1f402155a6d214835625325748d150", + "shasum": "" + }, + "require": { + "api-platform/metadata": "^3.4 || ^4.0", + "php": ">=8.2", + "psr/container": "^1.0 || ^2.0", + "symfony/http-kernel": "^6.4 || ^7.0" + }, + "require-dev": { + "api-platform/serializer": "^3.4 || ^4.0", + "api-platform/validator": "^3.4 || ^4.0", + "phpunit/phpunit": "^11.2", + "symfony/http-foundation": "^6.4 || ^7.0", + "symfony/web-link": "^6.4 || ^7.0", + "willdurand/negotiation": "^3.1" + }, + "suggest": { + "api-platform/serializer": "To use API Platform serializer.", + "api-platform/validator": "To use API Platform validation.", + "symfony/http-foundation": "To use our HTTP providers and processor.", + "symfony/web-link": "To support adding web links to the response headers.", + "willdurand/negotiation": "To use the API Platform content negoatiation provider." + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.0" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "ApiPlatform\\State\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr", + "homepage": "https://dunglas.fr" + }, + { + "name": "API Platform Community", + "homepage": "https://api-platform.com/community/contributors" + } + ], + "description": "API Platform State component ", + "homepage": "https://api-platform.com", + "keywords": [ + "Hydra", + "JSON-LD", + "api", + "graphql", + "hal", + "jsonapi", + "openapi", + "rest", + "swagger" + ], + "support": { + "source": "https://github.com/api-platform/state/tree/v4.0.15" + }, + "time": "2025-01-13T10:20:09+00:00" + }, + { + "name": "api-platform/symfony", + "version": "v4.0.15", + "source": { + "type": "git", + "url": "https://github.com/api-platform/symfony.git", + "reference": "e5956e32b5af1cee39e22a9e7820cc6a2a8a69e7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/api-platform/symfony/zipball/e5956e32b5af1cee39e22a9e7820cc6a2a8a69e7", + "reference": "e5956e32b5af1cee39e22a9e7820cc6a2a8a69e7", + "shasum": "" + }, + "require": { + "api-platform/documentation": "^3.4 || ^4.0", + "api-platform/http-cache": "^3.4 || ^4.0", + "api-platform/hydra": "^3.4 || ^4.0", + "api-platform/json-schema": "^3.4 || ^4.0", + "api-platform/jsonld": "^3.4 || ^4.0", + "api-platform/metadata": "^3.4 || ^4.0", + "api-platform/openapi": "^3.4 || ^4.0", + "api-platform/serializer": "^3.4 || ^4.0", + "api-platform/state": "^3.4 || ^4.0", + "api-platform/validator": "^3.4 || ^4.0", + "php": ">=8.2", + "symfony/property-access": "^6.4 || ^7.0", + "symfony/property-info": "^6.4 || ^7.0", + "symfony/security-core": "^6.4 || ^7.0", + "symfony/serializer": "^6.4 || ^7.0", + "willdurand/negotiation": "^3.1" + }, + "require-dev": { + "api-platform/doctrine-common": "^3.4 || ^4.0", + "api-platform/doctrine-odm": "^3.4 || ^4.0", + "api-platform/doctrine-orm": "^3.4 || ^4.0", + "api-platform/elasticsearch": "^3.4 || ^4.0", + "api-platform/graphql": "^3.4 || ^4.0", + "api-platform/parameter-validator": "^3.1", + "phpspec/prophecy-phpunit": "^2.2", + "phpunit/phpunit": "^11.2", + "symfony/expression-language": "^6.4 || ^7.0", + "symfony/mercure-bundle": "*", + "symfony/routing": "^6.4 || ^7.0", + "symfony/validator": "^6.4 || ^7.0", + "webonyx/graphql-php": "^15.0" + }, + "suggest": { + "api-platform/doctrine-odm": "To support MongoDB. Only versions 4.0 and later are supported.", + "api-platform/doctrine-orm": "To support Doctrine ORM.", + "api-platform/elasticsearch": "To support Elasticsearch.", + "api-platform/graphql": "To support GraphQL.", + "api-platform/ramsey-uuid": "To support Ramsey's UUID identifiers.", + "ocramius/package-versions": "To display the API Platform's version in the debug bar.", + "phpstan/phpdoc-parser": "To support extracting metadata from PHPDoc.", + "psr/cache-implementation": "To use metadata caching.", + "symfony/cache": "To have metadata caching when using Symfony integration.", + "symfony/config": "To load XML configuration files.", + "symfony/expression-language": "To use authorization and mercure advanced features.", + "symfony/http-client": "To use the HTTP cache invalidation system.", + "symfony/mercure-bundle": "To support mercure integration.", + "symfony/messenger": "To support messenger integration and asynchronous Mercure updates.", + "symfony/security": "To use authorization features.", + "symfony/twig-bundle": "To use the Swagger UI integration.", + "symfony/uid": "To support Symfony UUID/ULID identifiers.", + "symfony/web-profiler-bundle": "To use the data collector." + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.0" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "ApiPlatform\\Symfony\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr", + "homepage": "https://dunglas.fr" + }, + { + "name": "API Platform Community", + "homepage": "https://api-platform.com/community/contributors" + } + ], + "description": "Symfony API Platform integration", + "homepage": "https://api-platform.com", + "keywords": [ + "Hydra", + "JSON-LD", + "api", + "graphql", + "hal", + "jsonapi", + "openapi", + "rest", + "swagger", + "symfony" + ], + "support": { + "source": "https://github.com/api-platform/symfony/tree/v4.0.15" + }, + "time": "2025-01-17T08:54:48+00:00" + }, + { + "name": "api-platform/validator", + "version": "v4.0.15", + "source": { + "type": "git", + "url": "https://github.com/api-platform/validator.git", + "reference": "095b76546a16c3826441d93f63458b441fefffcb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/api-platform/validator/zipball/095b76546a16c3826441d93f63458b441fefffcb", + "reference": "095b76546a16c3826441d93f63458b441fefffcb", + "shasum": "" + }, + "require": { + "api-platform/metadata": "^3.4 || ^4.0", + "php": ">=8.2", + "symfony/web-link": "^6.4 || ^7.0" + }, + "require-dev": { + "phpspec/prophecy-phpunit": "^2.2", + "phpunit/phpunit": "^11.2", + "symfony/http-kernel": "^6.4 || ^7.0", + "symfony/serializer": "^6.4 || ^7.0", + "symfony/validator": "^6.4 || ^7.0" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.0" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "ApiPlatform\\Validator\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr", + "homepage": "https://dunglas.fr" + }, + { + "name": "API Platform Community", + "homepage": "https://api-platform.com/community/contributors" + } + ], + "description": "API Platform validator component", + "homepage": "https://api-platform.com", + "keywords": [ + "api", + "graphql", + "rest", + "validator" + ], + "support": { + "source": "https://github.com/api-platform/validator/tree/v4.1.0-alpha.1" + }, + "time": "2024-11-04T14:21:40+00:00" }, { "name": "beberlei/doctrineextensions", @@ -6020,6 +6904,85 @@ ], "time": "2024-09-09T11:45:10+00:00" }, + { + "name": "symfony/polyfill-uuid", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-uuid": "*" + }, + "suggest": { + "ext-uuid": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for uuid functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.31.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-09T11:45:10+00:00" + }, { "name": "symfony/property-access", "version": "v6.4.13", @@ -7297,6 +8260,155 @@ ], "time": "2024-09-25T14:18:03+00:00" }, + { + "name": "symfony/type-info", + "version": "v7.2.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/type-info.git", + "reference": "3b5a17470fff0034f25fd4287cbdaa0010d2f749" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/type-info/zipball/3b5a17470fff0034f25fd4287cbdaa0010d2f749", + "reference": "3b5a17470fff0034f25fd4287cbdaa0010d2f749", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/container": "^1.1|^2.0" + }, + "require-dev": { + "phpstan/phpdoc-parser": "^1.0|^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\TypeInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mathias Arlaud", + "email": "mathias.arlaud@gmail.com" + }, + { + "name": "Baptiste LEDUC", + "email": "baptiste.leduc@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts PHP types information.", + "homepage": "https://symfony.com", + "keywords": [ + "PHPStan", + "phpdoc", + "symfony", + "type" + ], + "support": { + "source": "https://github.com/symfony/type-info/tree/v7.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-20T13:38:37+00:00" + }, + { + "name": "symfony/uid", + "version": "v6.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/uid.git", + "reference": "18eb207f0436a993fffbdd811b5b8fa35fa5e007" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/uid/zipball/18eb207f0436a993fffbdd811b5b8fa35fa5e007", + "reference": "18eb207f0436a993fffbdd811b5b8fa35fa5e007", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/polyfill-uuid": "^1.15" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Uid\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to generate and represent UIDs", + "homepage": "https://symfony.com", + "keywords": [ + "UID", + "ulid", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/uid/tree/v6.4.13" + }, + "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:18:03+00:00" + }, { "name": "symfony/validator", "version": "v6.4.17", diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml index 0fe4c8d..1a4e0f3 100644 --- a/config/packages/api_platform.yaml +++ b/config/packages/api_platform.yaml @@ -30,9 +30,7 @@ api_platform: vary: ['Content-Type', 'Authorization', 'Origin'] extra_properties: standard_put: true - rfc_7807_compliant_errors: true - event_listeners_backward_compatibility_layer: false - keep_legacy_inflector: false + use_symfony_listeners: true swagger: api_keys: access_token: diff --git a/config/packages/uid.yaml b/config/packages/uid.yaml new file mode 100644 index 0000000..0152094 --- /dev/null +++ b/config/packages/uid.yaml @@ -0,0 +1,4 @@ +framework: + uid: + default_uuid_version: 7 + time_based_uuid_version: 7 diff --git a/symfony.lock b/symfony.lock index e21d55d..9c2a8de 100644 --- a/symfony.lock +++ b/symfony.lock @@ -13,6 +13,20 @@ "src/ApiResource/.gitignore" ] }, + "api-platform/symfony": { + "version": "4.0", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "4.0", + "ref": "e9952e9f393c2d048f10a78f272cd35e807d972b" + }, + "files": [ + "config/packages/api_platform.yaml", + "config/routes/api_platform.yaml", + "src/ApiResource/.gitignore" + ] + }, "doctrine/annotations": { "version": "2.0", "recipe": { @@ -231,6 +245,18 @@ "templates/base.html.twig" ] }, + "symfony/uid": { + "version": "6.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.2", + "ref": "d294ad4add3e15d7eb1bae0221588ca89b38e558" + }, + "files": [ + "config/packages/uid.yaml" + ] + }, "symfony/validator": { "version": "6.3", "recipe": { From 5db40652a35e52f4c5509093d3a29854a0e85771 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 13:20:24 +0100 Subject: [PATCH 65/76] Update iri converter injections to api-platform 4 namespace --- src/Gateway/Paypal/PaypalGateway.php | 6 +++--- src/Gateway/Stripe/StripeGateway.php | 2 +- src/State/Accounting/AccountingStateProvider.php | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Gateway/Paypal/PaypalGateway.php b/src/Gateway/Paypal/PaypalGateway.php index 41ec5a8..ecbf42d 100644 --- a/src/Gateway/Paypal/PaypalGateway.php +++ b/src/Gateway/Paypal/PaypalGateway.php @@ -2,7 +2,7 @@ namespace App\Gateway\Paypal; -use ApiPlatform\Api\IriConverterInterface; +use ApiPlatform\Metadata\IriConverterInterface; use App\Entity\Gateway\Charge; use App\Entity\Gateway\Checkout; use App\Gateway\ChargeType; @@ -45,10 +45,10 @@ class PaypalGateway implements GatewayInterface public function __construct( private PaypalService $paypal, - private EntityManagerInterface $entityManager, - private IriConverterInterface $iriConverter, private CheckoutService $checkoutService, private CheckoutRepository $checkoutRepository, + private EntityManagerInterface $entityManager, + private IriConverterInterface $iriConverter, ) {} public static function getName(): string diff --git a/src/Gateway/Stripe/StripeGateway.php b/src/Gateway/Stripe/StripeGateway.php index fe86b00..cf3791b 100644 --- a/src/Gateway/Stripe/StripeGateway.php +++ b/src/Gateway/Stripe/StripeGateway.php @@ -2,7 +2,7 @@ namespace App\Gateway\Stripe; -use ApiPlatform\Api\IriConverterInterface; +use ApiPlatform\Metadata\IriConverterInterface; use App\Entity\Gateway\Checkout; use App\Entity\User\User; use App\Gateway\ChargeType; diff --git a/src/State/Accounting/AccountingStateProvider.php b/src/State/Accounting/AccountingStateProvider.php index fb4eb11..9543437 100644 --- a/src/State/Accounting/AccountingStateProvider.php +++ b/src/State/Accounting/AccountingStateProvider.php @@ -2,7 +2,6 @@ namespace App\State\Accounting; -use ApiPlatform\Api\IriConverterInterface; use ApiPlatform\Doctrine\Orm\State\CollectionProvider; use ApiPlatform\Doctrine\Orm\State\ItemProvider; use ApiPlatform\Metadata\CollectionOperationInterface; @@ -23,7 +22,6 @@ class AccountingStateProvider implements ProviderInterface private ProviderInterface $collectionProvider, private AutoMapper $autoMapper, private AccountingService $accountingService, - private IriConverterInterface $iriConverter, ) {} public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null From 61c5fabff4baff2e2e6f0aa1241b38ffff12da79 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 13:25:36 +0100 Subject: [PATCH 66/76] Update hydra convention in test --- tests/Entity/ProjectApiTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Entity/ProjectApiTest.php b/tests/Entity/ProjectApiTest.php index 278ad27..7a3d1eb 100644 --- a/tests/Entity/ProjectApiTest.php +++ b/tests/Entity/ProjectApiTest.php @@ -29,9 +29,9 @@ class ProjectApiTest extends ApiTestCase $this->assertResponseIsSuccessful(); $this->assertJsonContains(['@id' => '/v4/projects']); - $this->assertJsonContains(['@type' => 'hydra:Collection']); - $this->assertJsonContains(['hydra:totalItems' => 0]); - $this->assertJsonContains(['hydra:member' => []]); + $this->assertJsonContains(['@type' => 'Collection']); + $this->assertJsonContains(['totalItems' => 0]); + $this->assertJsonContains(['member' => []]); $owner = new User(); $owner->setUsername('test_user'); @@ -50,8 +50,8 @@ class ProjectApiTest extends ApiTestCase static::createClient()->request('GET', '/v4/projects'); $this->assertResponseIsSuccessful(); - $this->assertJsonContains(['hydra:totalItems' => 1]); - $this->assertJsonContains(['hydra:member' => [ + $this->assertJsonContains(['totalItems' => 1]); + $this->assertJsonContains(['member' => [ [ 'title' => 'Test Project', 'status' => ProjectStatus::InEditing->value, From 78623c97e405b7992b01d241d28d3af60ddba9a6 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 13:32:46 +0100 Subject: [PATCH 67/76] Remove unused dependency subiabre/doctrine-snowflakes --- composer.json | 1 - composer.lock | 113 +------------------------------------------------- 2 files changed, 1 insertion(+), 113 deletions(-) diff --git a/composer.json b/composer.json index 1d70080..3021a73 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,6 @@ "phpstan/phpdoc-parser": "^1.24", "stof/doctrine-extensions-bundle": "^1.11", "stripe/stripe-php": "^15.0", - "subiabre/doctrine-snowflakes": "^2.0", "symfony/asset": "6.4.*", "symfony/cache": "6.4.*", "symfony/console": "6.4.*", diff --git a/composer.lock b/composer.lock index 124bb9d..609b0a2 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": "6b7778236794d7ea905247c502a8189d", + "content-hash": "d4be2f29c15fc341c9b15c73f396bbf1", "packages": [ { "name": "api-platform/doctrine-common", @@ -3009,73 +3009,6 @@ ], "time": "2024-10-07T22:30:27+00:00" }, - { - "name": "godruoyi/php-snowflake", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/godruoyi/php-snowflake.git", - "reference": "eacdba18c157aab2d567f499ca1865b7fff2bdfa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/godruoyi/php-snowflake/zipball/eacdba18c157aab2d567f499ca1865b7fff2bdfa", - "reference": "eacdba18c157aab2d567f499ca1865b7fff2bdfa", - "shasum": "" - }, - "require": { - "php-64bit": ">=8.1" - }, - "require-dev": { - "ext-redis": "*", - "ext-swoole": "*", - "illuminate/contracts": "^10.0 || ^11.0", - "laravel/pint": "^1.10", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^10", - "predis/predis": "^2.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Godruoyi\\Snowflake\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Godruoyi", - "email": "g@godruoyi.com" - } - ], - "description": "An ID Generator for PHP based on Snowflake Algorithm (Twitter announced).", - "homepage": "https://github.com/godruoyi/php-snowflake", - "keywords": [ - "Unique ID", - "laravel snowflake", - "order id", - "php snowflake", - "php sonyflake", - "php unique id", - "snowflake algorithm", - "sonyflake", - "unique order id" - ], - "support": { - "issues": "https://github.com/godruoyi/php-snowflake/issues", - "source": "https://github.com/godruoyi/php-snowflake/tree/3.1.1" - }, - "funding": [ - { - "url": "https://images.godruoyi.com/wechat.png", - "type": "custom" - } - ], - "time": "2024-11-22T14:18:15+00:00" - }, { "name": "jolicode/automapper", "version": "9.2.0", @@ -4333,50 +4266,6 @@ }, "time": "2024-09-18T18:38:30+00:00" }, - { - "name": "subiabre/doctrine-snowflakes", - "version": "2.0", - "source": { - "type": "git", - "url": "https://github.com/subiabre/doctrine-snowflakes.git", - "reference": "f179b7aba6f4d08d455b3369b0af4903693de489" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/subiabre/doctrine-snowflakes/zipball/f179b7aba6f4d08d455b3369b0af4903693de489", - "reference": "f179b7aba6f4d08d455b3369b0af4903693de489", - "shasum": "" - }, - "require": { - "doctrine/orm": "^2.16", - "godruoyi/php-snowflake": "^3.0" - }, - "require-dev": { - "phpunit/phpunit": "^10.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Subiabre\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Subiabre", - "email": "subiabrewd@gmail.com" - } - ], - "description": "Custom id generator implementing snowflake algorithm", - "support": { - "issues": "https://github.com/subiabre/doctrine-snowflakes/issues", - "source": "https://github.com/subiabre/doctrine-snowflakes/tree/2.0" - }, - "time": "2023-11-13T19:04:37+00:00" - }, { "name": "symfony/asset", "version": "v6.4.13", From 280ec186d605af014c9f2cb77cd266694a96d9ac Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 13:51:14 +0100 Subject: [PATCH 68/76] Upgrade doctrine/orm to ^3.0 --- composer.json | 10 ++++----- composer.lock | 58 ++++++++++++++++++++------------------------------- symfony.lock | 2 +- 3 files changed, 29 insertions(+), 41 deletions(-) diff --git a/composer.json b/composer.json index 3021a73..d44c58c 100644 --- a/composer.json +++ b/composer.json @@ -13,15 +13,15 @@ "brick/math": "^0.11.0", "brick/money": "^0.8.1", "doctrine/dbal": "^3", - "doctrine/doctrine-bundle": "^2.12", - "doctrine/doctrine-migrations-bundle": "^3.3", - "doctrine/orm": "^2.19", + "doctrine/doctrine-bundle": "^2.13", + "doctrine/doctrine-migrations-bundle": "^3.4", + "doctrine/orm": "^3.3", "doctrineencryptbundle/doctrine-encrypt-bundle": "^5.4", "jolicode/automapper": "^9.2", "nelmio/cors-bundle": "^2.3", "phpdocumentor/reflection-docblock": "^5.3", "phpstan/phpdoc-parser": "^1.24", - "stof/doctrine-extensions-bundle": "^1.11", + "stof/doctrine-extensions-bundle": "^1.13", "stripe/stripe-php": "^15.0", "symfony/asset": "6.4.*", "symfony/cache": "6.4.*", @@ -96,7 +96,7 @@ "symfony/browser-kit": "6.4.*", "symfony/css-selector": "6.4.*", "symfony/maker-bundle": "^1.51", - "symfony/phpunit-bridge": "^7.0", + "symfony/phpunit-bridge": "^7.2", "zenstruck/foundry": "^2.3" } } diff --git a/composer.lock b/composer.lock index 609b0a2..e231d2c 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": "d4be2f29c15fc341c9b15c73f396bbf1", + "content-hash": "c53fe446cadf36d31749b877915135c4", "packages": [ { "name": "api-platform/doctrine-common", @@ -2558,62 +2558,50 @@ }, { "name": "doctrine/orm", - "version": "2.20.1", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "e3cabade99ebccc6ba078884c1c5f250866a494e" + "reference": "b1f8253105aa5382c495e5f9f8ef34e297775428" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/e3cabade99ebccc6ba078884c1c5f250866a494e", - "reference": "e3cabade99ebccc6ba078884c1c5f250866a494e", + "url": "https://api.github.com/repos/doctrine/orm/zipball/b1f8253105aa5382c495e5f9f8ef34e297775428", + "reference": "b1f8253105aa5382c495e5f9f8ef34e297775428", "shasum": "" }, "require": { "composer-runtime-api": "^2", - "doctrine/cache": "^1.12.1 || ^2.1.1", - "doctrine/collections": "^1.5 || ^2.1", - "doctrine/common": "^3.0.3", - "doctrine/dbal": "^2.13.1 || ^3.2", + "doctrine/collections": "^2.2", + "doctrine/dbal": "^3.8.2 || ^4", "doctrine/deprecations": "^0.5.3 || ^1", "doctrine/event-manager": "^1.2 || ^2", "doctrine/inflector": "^1.4 || ^2.0", "doctrine/instantiator": "^1.3 || ^2", - "doctrine/lexer": "^2 || ^3", - "doctrine/persistence": "^2.4 || ^3", + "doctrine/lexer": "^3", + "doctrine/persistence": "^3.3.1 || ^4", "ext-ctype": "*", - "php": "^7.1 || ^8.0", + "php": "^8.1", "psr/cache": "^1 || ^2 || ^3", - "symfony/console": "^4.2 || ^5.0 || ^6.0 || ^7.0", - "symfony/polyfill-php72": "^1.23", - "symfony/polyfill-php80": "^1.16" - }, - "conflict": { - "doctrine/annotations": "<1.13 || >= 3.0" + "symfony/console": "^5.4 || ^6.0 || ^7.0", + "symfony/var-exporter": "^6.3.9 || ^7.0" }, "require-dev": { - "doctrine/annotations": "^1.13 || ^2", - "doctrine/coding-standard": "^9.0.2 || ^12.0", - "phpbench/phpbench": "^0.16.10 || ^1.0", - "phpstan/extension-installer": "~1.1.0 || ^1.4", - "phpstan/phpstan": "~1.4.10 || 2.0.3", - "phpstan/phpstan-deprecation-rules": "^1 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6", + "doctrine/coding-standard": "^12.0", + "phpbench/phpbench": "^1.0", + "phpdocumentor/guides-cli": "^1.4", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "2.0.3", + "phpstan/phpstan-deprecation-rules": "^2", + "phpunit/phpunit": "^10.4.0", "psr/log": "^1 || ^2 || ^3", "squizlabs/php_codesniffer": "3.7.2", - "symfony/cache": "^4.4 || ^5.4 || ^6.4 || ^7.0", - "symfony/var-exporter": "^4.4 || ^5.4 || ^6.2 || ^7.0", - "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0" + "symfony/cache": "^5.4 || ^6.2 || ^7.0" }, "suggest": { "ext-dom": "Provides support for XSD validation for XML mapping files", - "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0", - "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" + "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0" }, - "bin": [ - "bin/doctrine" - ], "type": "library", "autoload": { "psr-4": { @@ -2654,9 +2642,9 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/2.20.1" + "source": "https://github.com/doctrine/orm/tree/3.3.1" }, - "time": "2024-12-19T06:48:36+00:00" + "time": "2024-12-19T07:08:14+00:00" }, { "name": "doctrine/persistence", diff --git a/symfony.lock b/symfony.lock index 9c2a8de..ff7a9f5 100644 --- a/symfony.lock +++ b/symfony.lock @@ -105,7 +105,7 @@ ] }, "stof/doctrine-extensions-bundle": { - "version": "1.11", + "version": "1.13", "recipe": { "repo": "github.com/symfony/recipes-contrib", "branch": "main", From 55488590a50909bf5ef5e1c2f04e21d37a88ddf0 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 13:51:23 +0100 Subject: [PATCH 69/76] Disable annotations support --- config/packages/framework.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index 6d85c29..085b3ae 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -18,6 +18,9 @@ framework: php_errors: log: true + annotations: + enabled: false + when@test: framework: test: true From ef61c83894ce84aff4941e786c3496244089e6a8 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 14:02:29 +0100 Subject: [PATCH 70/76] Disable controller_resolver.auto_mapping --- config/packages/doctrine.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index f03a88d..1a85420 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -22,7 +22,6 @@ doctrine: dir: '%kernel.project_dir%/src/Entity' prefix: 'App\Entity' alias: App - gedmo_loggable: type: attribute prefix: Gedmo\Loggable\Entity @@ -31,6 +30,8 @@ doctrine: dql: string_functions: instr: DoctrineExtensions\Query\Mysql\Instr + controller_resolver: + auto_mapping: false when@test: doctrine: From 21e54c91acbb66caa49ef9c57103a94085427c09 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 14:04:53 +0100 Subject: [PATCH 71/76] Bump php-cs-fixer --- composer.json | 2 +- composer.lock | 52 +++++++++++++++++++++++++-------------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/composer.json b/composer.json index d44c58c..c712380 100644 --- a/composer.json +++ b/composer.json @@ -91,7 +91,7 @@ } }, "require-dev": { - "friendsofphp/php-cs-fixer": "3.64", + "friendsofphp/php-cs-fixer": "^3.68", "phpunit/phpunit": "^9.5", "symfony/browser-kit": "6.4.*", "symfony/css-selector": "6.4.*", diff --git a/composer.lock b/composer.lock index e231d2c..61bbbb2 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": "c53fe446cadf36d31749b877915135c4", + "content-hash": "60e2eb3df89fbc45c59e9512d650d822", "packages": [ { "name": "api-platform/doctrine-common", @@ -9278,16 +9278,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.64.0", + "version": "v3.68.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "58dd9c931c785a79739310aef5178928305ffa67" + "reference": "b9db2b2ea3cdba7201067acee46f984ef2397cff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/58dd9c931c785a79739310aef5178928305ffa67", - "reference": "58dd9c931c785a79739310aef5178928305ffa67", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/b9db2b2ea3cdba7201067acee46f984ef2397cff", + "reference": "b9db2b2ea3cdba7201067acee46f984ef2397cff", "shasum": "" }, "require": { @@ -9297,38 +9297,38 @@ "ext-filter": "*", "ext-json": "*", "ext-tokenizer": "*", - "fidry/cpu-core-counter": "^1.0", + "fidry/cpu-core-counter": "^1.2", "php": "^7.4 || ^8.0", "react/child-process": "^0.6.5", "react/event-loop": "^1.0", "react/promise": "^2.0 || ^3.0", "react/socket": "^1.0", "react/stream": "^1.0", - "sebastian/diff": "^4.0 || ^5.0 || ^6.0", - "symfony/console": "^5.4 || ^6.0 || ^7.0", - "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0", - "symfony/filesystem": "^5.4 || ^6.0 || ^7.0", - "symfony/finder": "^5.4 || ^6.0 || ^7.0", - "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0", - "symfony/polyfill-mbstring": "^1.28", - "symfony/polyfill-php80": "^1.28", - "symfony/polyfill-php81": "^1.28", - "symfony/process": "^5.4 || ^6.0 || ^7.0", - "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0" + "sebastian/diff": "^4.0 || ^5.1 || ^6.0", + "symfony/console": "^5.4 || ^6.4 || ^7.0", + "symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0", + "symfony/filesystem": "^5.4 || ^6.4 || ^7.0", + "symfony/finder": "^5.4 || ^6.4 || ^7.0", + "symfony/options-resolver": "^5.4 || ^6.4 || ^7.0", + "symfony/polyfill-mbstring": "^1.31", + "symfony/polyfill-php80": "^1.31", + "symfony/polyfill-php81": "^1.31", + "symfony/process": "^5.4 || ^6.4 || ^7.2", + "symfony/stopwatch": "^5.4 || ^6.4 || ^7.0" }, "require-dev": { - "facile-it/paraunit": "^1.3 || ^2.3", - "infection/infection": "^0.29.5", - "justinrainbow/json-schema": "^5.2", + "facile-it/paraunit": "^1.3.1 || ^2.4", + "infection/infection": "^0.29.8", + "justinrainbow/json-schema": "^5.3 || ^6.0", "keradus/cli-executor": "^2.1", - "mikey179/vfsstream": "^1.6.11", + "mikey179/vfsstream": "^1.6.12", "php-coveralls/php-coveralls": "^2.7", "php-cs-fixer/accessible-object": "^1.1", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.5", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.5", - "phpunit/phpunit": "^9.6.19 || ^10.5.21 || ^11.2", - "symfony/var-dumper": "^5.4 || ^6.0 || ^7.0", - "symfony/yaml": "^5.4 || ^6.0 || ^7.0" + "phpunit/phpunit": "^9.6.22 || ^10.5.40 || ^11.5.2", + "symfony/var-dumper": "^5.4.48 || ^6.4.15 || ^7.2.0", + "symfony/yaml": "^5.4.45 || ^6.4.13 || ^7.2.0" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -9369,7 +9369,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.64.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.68.1" }, "funding": [ { @@ -9377,7 +9377,7 @@ "type": "github" } ], - "time": "2024-08-30T23:09:38+00:00" + "time": "2025-01-17T09:20:36+00:00" }, { "name": "masterminds/html5", From ba509b5d9db1856fe38a9ef379431d4d537928d9 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 14:10:35 +0100 Subject: [PATCH 72/76] Update php-cs-fixer workflow --- .github/workflows/php-cs-fixer.yaml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/php-cs-fixer.yaml b/.github/workflows/php-cs-fixer.yaml index c0f0dd7..7ff2e9f 100644 --- a/.github/workflows/php-cs-fixer.yaml +++ b/.github/workflows/php-cs-fixer.yaml @@ -1,17 +1,20 @@ name: PHP CS Fixer + on: [pull_request] + +env: + PHP_VERSION: '8.3' + jobs: php-cs-fixer: - runs-on: "ubuntu-latest" + runs-on: ubuntu-latest + steps: - - name: Setup PHP 8.3 - uses: shivammathur/setup-php@v2 + - uses: actions/checkout@v4 + + - uses: php-actions/composer@v6 with: - php-version: '8.3' - tools: php-cs-fixer:3.64 - - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Run PHP CS Fixer + php_version: ${{ env.PHP_VERSION }} + + - name: PHP CS Fixer run: php-cs-fixer check From 2a0131f7eb041fd36da5b88119d3cecacd675c63 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 14:24:53 +0100 Subject: [PATCH 73/76] Code style updates by php-cs-fixer --- src/Gateway/GatewayInterface.php | 2 +- src/Gateway/Wallet/WalletService.php | 2 +- src/Library/Benzina/Benzina.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Gateway/GatewayInterface.php b/src/Gateway/GatewayInterface.php index cfe8639..7e736af 100644 --- a/src/Gateway/GatewayInterface.php +++ b/src/Gateway/GatewayInterface.php @@ -29,7 +29,7 @@ interface GatewayInterface public static function getName(): string; /** - * @return \App\Gateway\ChargeType[] The charge types that can be processed by this Gateway + * @return ChargeType[] The charge types that can be processed by this Gateway */ public static function getSupportedChargeTypes(): array; diff --git a/src/Gateway/Wallet/WalletService.php b/src/Gateway/Wallet/WalletService.php index 66c8428..3ef2724 100644 --- a/src/Gateway/Wallet/WalletService.php +++ b/src/Gateway/Wallet/WalletService.php @@ -21,7 +21,7 @@ class WalletService ) {} /** - * @return \App\Entity\WalletStatement[] + * @return WalletStatement[] */ public function getStatements(Accounting $accounting): array { diff --git a/src/Library/Benzina/Benzina.php b/src/Library/Benzina/Benzina.php index 99fdede..5cc7e87 100644 --- a/src/Library/Benzina/Benzina.php +++ b/src/Library/Benzina/Benzina.php @@ -7,7 +7,7 @@ use App\Library\Benzina\Stream\StreamInterface; class Benzina { - /** @var Pump\PumpInterface[] */ + /** @var PumpInterface[] */ private array $availablePumps = []; public function __construct( From c21483654bca5ff1dd96e38e0ba816339d3af61f Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 14:32:49 +0100 Subject: [PATCH 74/76] Add pdo_mysql extension to cs fixer workflow --- .github/workflows/php-cs-fixer.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/php-cs-fixer.yaml b/.github/workflows/php-cs-fixer.yaml index 7ff2e9f..9315748 100644 --- a/.github/workflows/php-cs-fixer.yaml +++ b/.github/workflows/php-cs-fixer.yaml @@ -4,6 +4,7 @@ on: [pull_request] env: PHP_VERSION: '8.3' + PHP_EXTENSIONS: pdo_mysql jobs: php-cs-fixer: @@ -15,6 +16,7 @@ jobs: - uses: php-actions/composer@v6 with: php_version: ${{ env.PHP_VERSION }} - + php_extensions: ${{ env.PHP_EXTENSIONS }} + - name: PHP CS Fixer run: php-cs-fixer check From bef77a3b92cdc7eb6ef109ca497ded36cff68d11 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 14:34:38 +0100 Subject: [PATCH 75/76] Add stripe api key from secrets --- .github/workflows/php-cs-fixer.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/php-cs-fixer.yaml b/.github/workflows/php-cs-fixer.yaml index 9315748..35677ba 100644 --- a/.github/workflows/php-cs-fixer.yaml +++ b/.github/workflows/php-cs-fixer.yaml @@ -10,6 +10,9 @@ jobs: php-cs-fixer: runs-on: ubuntu-latest + env: + STRIPE_API_KEY: ${{ secrets.STRIPE_API_KEY }} + steps: - uses: actions/checkout@v4 From 2b8dd20d33422a8101a2c7be381c7f68f3b41a89 Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 17 Jan 2025 14:40:57 +0100 Subject: [PATCH 76/76] Update cs fixer exec command --- .github/workflows/php-cs-fixer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php-cs-fixer.yaml b/.github/workflows/php-cs-fixer.yaml index 35677ba..b153c55 100644 --- a/.github/workflows/php-cs-fixer.yaml +++ b/.github/workflows/php-cs-fixer.yaml @@ -22,4 +22,4 @@ jobs: php_extensions: ${{ env.PHP_EXTENSIONS }} - name: PHP CS Fixer - run: php-cs-fixer check + run: php ./vendor/bin/php-cs-fixer check