diff --git a/config/services.yaml b/config/services.yaml index 9d25d0aa09c..54df97fba21 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -110,6 +110,8 @@ services: tags: [ 'app.auth_app.url_generator' ] App\Recaptcha\RecaptchaApiClientInterface: tags: ['app.recaptcha_api_client'] + App\SendInBlue\Manager\ManagerInterface: + tags: ['app.sendinblue.manager'] # Imports App\: @@ -366,3 +368,15 @@ services: arguments: - '@request_stack' - '%kernel.debug%' + + App\SendInBlue\ContactManager: + arguments: + $managers: !tagged_iterator 'app.sendinblue.manager' + + App\SendInBlue\Manager\AdherentManager: + arguments: + $listId: '%env(int:SENDINBLUE_ADHERENT_LIST_ID)%' + + App\SendInBlue\Manager\ContactManager: + arguments: + $listId: '%env(int:SENDINBLUE_CONTACT_LIST_ID)%' diff --git a/config/services_dev.yaml b/config/services_dev.yaml index ffac019631d..3cde1c3dd58 100644 --- a/config/services_dev.yaml +++ b/config/services_dev.yaml @@ -32,8 +32,8 @@ services: App\OpenGraph\OpenGraphFetcher: class: 'Tests\App\Test\OpenGraph\DummyOpenGraphFetcher' - Tests\App\Test\SendInBlue\DummyClient: - decorates: 'App\SendInBlue\Client' + Tests\App\Test\SendInBlue\Client\DummyClient: + decorates: 'App\SendInBlue\Client\Client' data_collector.messenger: class: Symfony\Component\Messenger\DataCollector\MessengerDataCollector diff --git a/config/services_test.yaml b/config/services_test.yaml index 81ec55d5d2f..3965be5603b 100644 --- a/config/services_test.yaml +++ b/config/services_test.yaml @@ -79,4 +79,4 @@ services: $accessTokenTtlInterval: '%env(ACCESS_TOKEN_TTL_INTERVAL)%' $refreshTokenTtlInterval: '%env(REFRESH_TOKEN_TTL_INTERVAL)%' - App\SendInBlue\Client: '@Tests\App\Test\SendInBlue\DummyClient' + App\SendInBlue\Client\Client: '@Tests\App\Test\SendInBlue\Client\DummyClient' diff --git a/src/Contact/ContactHandler.php b/src/Contact/ContactHandler.php index 171e54247e7..bb4127205f4 100644 --- a/src/Contact/ContactHandler.php +++ b/src/Contact/ContactHandler.php @@ -4,7 +4,7 @@ use App\Entity\Contact; use App\Membership\Contact\ContactRegistrationCommand; -use App\Membership\Contact\ContactSynchronisationCommand; +use App\SendInBlue\Command\ContactSynchronisationCommand; use Symfony\Component\Messenger\MessageBusInterface; class ContactHandler diff --git a/src/Entity/Adherent.php b/src/Entity/Adherent.php index ba9a0cabdbb..642ab4fbaba 100644 --- a/src/Entity/Adherent.php +++ b/src/Entity/Adherent.php @@ -42,6 +42,7 @@ use App\OAuth\Model\User as InMemoryOAuthUser; use App\Scope\FeatureEnum; use App\Scope\ScopeEnum; +use App\SendInBlue\ContactInterface; use App\Subscription\SubscriptionTypeEnum; use App\Utils\AreaUtils; use App\Validator\TerritorialCouncil\UniqueTerritorialCouncilMember; @@ -98,7 +99,7 @@ * * @UniqueTerritorialCouncilMember(qualities={"referent", "lre_manager", "referent_jam"}) */ -class Adherent implements UserInterface, UserEntityInterface, GeoPointInterface, EncoderAwareInterface, MembershipInterface, ReferentTaggableEntity, ZoneableEntity, \Serializable, EntityMediaInterface, EquatableInterface, UuidEntityInterface, MailchimpCleanableContactInterface +class Adherent implements UserInterface, UserEntityInterface, GeoPointInterface, EncoderAwareInterface, MembershipInterface, ReferentTaggableEntity, ZoneableEntity, \Serializable, EntityMediaInterface, EquatableInterface, UuidEntityInterface, MailchimpCleanableContactInterface, ContactInterface { use EntityCrudTrait; use EntityIdentityTrait; diff --git a/src/Entity/Contact.php b/src/Entity/Contact.php index 42c4ab8192b..37a64467928 100644 --- a/src/Entity/Contact.php +++ b/src/Entity/Contact.php @@ -5,6 +5,7 @@ use ApiPlatform\Core\Annotation\ApiResource; use App\Recaptcha\RecaptchaChallengeInterface; use App\Recaptcha\RecaptchaChallengeTrait; +use App\SendInBlue\ContactInterface; use App\Validator\Recaptcha as AssertRecaptcha; use Doctrine\ORM\Mapping as ORM; use libphonenumber\PhoneNumber; @@ -47,7 +48,7 @@ * * @AssertRecaptcha(api="friendly_captcha", groups={"contact_create"}) */ -class Contact implements RecaptchaChallengeInterface +class Contact implements RecaptchaChallengeInterface, ContactInterface { use EntityIdentityTrait; use EntityPostAddressTrait; diff --git a/src/SendInBlue/AdherentManager.php b/src/SendInBlue/AdherentManager.php deleted file mode 100644 index 96f38c43b3f..00000000000 --- a/src/SendInBlue/AdherentManager.php +++ /dev/null @@ -1,72 +0,0 @@ -client = $client; - $this->adherentListId = $sendInBlueAdherentListId; - } - - public function synchronize(Adherent $adherent, string $identifier): void - { - $this->client->synchronize( - $identifier, - $this->adherentListId, - $this->createAttributes($adherent) - ); - } - - public function delete(Adherent $adherent): void - { - $this->client->delete($adherent->getEmailAddress()); - } - - private function createAttributes(Adherent $adherent): array - { - return [ - self::FIELD_EMAIL => $adherent->getEmailAddress(), - - self::FIELD_SOURCE => $adherent->getSource(), - self::FIELD_FIRST_NAME => $adherent->getFirstName(), - self::FIELD_LAST_NAME => $adherent->getLastName(), - - self::FIELD_BIRTHDATE => $adherent->getBirthdate() ? $adherent->getBirthdate()->format('Y-m-d') : null, - self::FIELD_PHONE => PhoneNumberUtils::format($adherent->getPhone()), - - self::FIELD_CITY => $adherent->getCityName(), - self::FIELD_POSTAL_CODE => $adherent->getPostalCode(), - self::FIELD_COUNTRY => $adherent->getCountry(), - - self::FIELD_STATUS => $adherent->getStatus(), - self::FIELD_CREATED_AT => $adherent->getRegisteredAt() ? $adherent->getRegisteredAt()->format('Y-m-d') : null, - self::FIELD_UPDATED_AT => $adherent->getUpdatedAt() ? $adherent->getUpdatedAt()->format('Y-m-d') : null, - self::FIELD_ACTIVATED_AT => $adherent->getActivatedAt() ? $adherent->getActivatedAt()->format('Y-m-d') : null, - - self::FIELD_SUBSCRIPTION_TYPES => implode(',', $adherent->getSubscriptionTypeCodes()), - ]; - } -} diff --git a/src/SendInBlue/AttributesEnum.php b/src/SendInBlue/AttributesEnum.php new file mode 100644 index 00000000000..6c535f034f7 --- /dev/null +++ b/src/SendInBlue/AttributesEnum.php @@ -0,0 +1,34 @@ +client = $client; - $this->contactListId = $sendInBlueContactListId; + $this->managers = $managers; } - public function synchronize(Contact $contact): void + public function synchronize(ContactInterface $contact, string $identifier): void { + $manager = $this->getManager($contact); + $this->client->synchronize( - $contact->getEmailAddress(), - $this->contactListId, - $this->createAttributes($contact) + $identifier, + $manager->getListId(), + $manager->getAttributes($contact) ); } - private function createAttributes(Contact $contact): array + public function delete(ContactInterface $contact): void + { + $manager = $this->getManager($contact); + + $this->client->delete($manager->getIdentifier($contact)); + } + + private function getManager(ContactInterface $contact): ManagerInterface { - return [ - self::FIELD_SOURCE => $contact->getSource(), - self::FIELD_FIRST_NAME => $contact->getFirstName(), - self::FIELD_LAST_NAME => $contact->getLastName(), - self::FIELD_ACTION_TERRAIN => \in_array(InterestEnum::ACTION_TERRAIN, $contact->getInterests(), true), - self::FIELD_CAMPAGNE_NUMERIQUE => \in_array(InterestEnum::CAMPAGNE_NUMERIQUE, $contact->getInterests(), true), - self::FIELD_PROCHES => \in_array(InterestEnum::PROCHES, $contact->getInterests(), true), - self::FIELD_INTERESTS_UPDATED_AT => $contact->getInterestsUpdatedAt(), - self::FIELD_BIRTHDATE => $contact->getBirthdate() ? $contact->getBirthdate()->format('Y-m-d') : null, - self::FIELD_PHONE => PhoneNumberUtils::format($contact->getPhone()), - self::FIELD_MAIL_CONTACT => $contact->isMailContact(), - self::FIELD_PHONE_CONTACT => $contact->isPhoneContact(), - self::FIELD_CITY => $contact->getCityName(), - self::FIELD_POSTAL_CODE => $contact->getPostalCode(), - self::FIELD_COUNTRY => $contact->getCountry(), - self::FIELD_CREATED_AT => $contact->getCreatedAt() ? $contact->getCreatedAt()->format('Y-m-d') : null, - self::FIELD_UPDATED_AT => $contact->getUpdatedAt() ? $contact->getUpdatedAt()->format('Y-m-d') : null, - ]; + foreach ($this->managers as $manager) { + if ($manager->supports($contact)) { + return $manager; + } + } + + throw new \InvalidArgumentException('Unhandled'); } } diff --git a/src/SendInBlue/Exception/UnexpectedTypeException.php b/src/SendInBlue/Exception/UnexpectedTypeException.php new file mode 100644 index 00000000000..c60d1e6967a --- /dev/null +++ b/src/SendInBlue/Exception/UnexpectedTypeException.php @@ -0,0 +1,11 @@ +em = $em; $this->adherentRepository = $adherentRepository; - $this->adherentManager = $adherentManager; + $this->contactManager = $contactManager; $this->logger = $logger; } @@ -44,7 +44,7 @@ public function __invoke(AdherentDeleteCommand $command): void $this->em->refresh($adherent); try { - $this->adherentManager->delete($adherent); + $this->contactManager->delete($adherent); } catch (\Exception $e) { $this->logger->error(sprintf('Failed to delete adherent UUID: "%s". Error: %s', $adherent->getUuid(), $e->getMessage())); } diff --git a/src/SendInBlue/Handler/AdherentSynchronisationCommandHandler.php b/src/SendInBlue/Handler/AdherentSynchronisationCommandHandler.php index b225bedb2d5..a271d0305f1 100644 --- a/src/SendInBlue/Handler/AdherentSynchronisationCommandHandler.php +++ b/src/SendInBlue/Handler/AdherentSynchronisationCommandHandler.php @@ -4,8 +4,8 @@ use App\Entity\Adherent; use App\Repository\AdherentRepository; -use App\SendInBlue\AdherentManager; use App\SendInBlue\Command\AdherentSynchronisationCommand; +use App\SendInBlue\ContactManager; use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; @@ -18,17 +18,17 @@ class AdherentSynchronisationCommandHandler implements MessageHandlerInterface, private EntityManagerInterface $em; private AdherentRepository $adherentRepository; - private AdherentManager $adherentManager; + private ContactManager $contactManager; public function __construct( EntityManagerInterface $em, AdherentRepository $adherentRepository, - AdherentManager $adherentManager, + ContactManager $contactManager, LoggerInterface $logger ) { $this->em = $em; $this->adherentRepository = $adherentRepository; - $this->adherentManager = $adherentManager; + $this->contactManager = $contactManager; $this->logger = $logger; } @@ -44,7 +44,7 @@ public function __invoke(AdherentSynchronisationCommand $command): void $this->em->refresh($adherent); try { - $this->adherentManager->synchronize($adherent, $command->getIdentifier()); + $this->contactManager->synchronize($adherent, $command->getIdentifier()); } catch (\Exception $e) { $this->logger->error(sprintf('Failed to synchronize adherent UUID: "%s". Error: %s', $adherent->getUuid(), $e->getMessage())); } diff --git a/src/Membership/Contact/ContactSynchronisationCommandHandler.php b/src/SendInBlue/Handler/ContactSynchronisationCommandHandler.php similarity index 91% rename from src/Membership/Contact/ContactSynchronisationCommandHandler.php rename to src/SendInBlue/Handler/ContactSynchronisationCommandHandler.php index 3d9fdc2982e..2b02ef2b523 100644 --- a/src/Membership/Contact/ContactSynchronisationCommandHandler.php +++ b/src/SendInBlue/Handler/ContactSynchronisationCommandHandler.php @@ -1,10 +1,11 @@ contactManager->synchronize($contact); + $this->contactManager->synchronize($contact, $contact->getEmailAddress()); } catch (\Exception $e) { $this->logger->error(sprintf('Failed to synchronize contact UUID: "%s". Error: %s', $contact->getUuid(), $e->getMessage())); } diff --git a/src/SendInBlue/Manager/AbstractManager.php b/src/SendInBlue/Manager/AbstractManager.php new file mode 100644 index 00000000000..128557b9331 --- /dev/null +++ b/src/SendInBlue/Manager/AbstractManager.php @@ -0,0 +1,31 @@ +listId = $listId; + } + + public function getListId(): int + { + return $this->listId; + } + + protected static function formatDate(?\DateTimeInterface $date): ?string + { + return $date ? $date->format('Y-m-d') : null; + } + + protected static function formatPhone(?PhoneNumber $phoneNumber): string + { + return PhoneNumberUtils::format($phoneNumber); + } +} diff --git a/src/SendInBlue/Manager/AdherentManager.php b/src/SendInBlue/Manager/AdherentManager.php new file mode 100644 index 00000000000..2074f46a2c5 --- /dev/null +++ b/src/SendInBlue/Manager/AdherentManager.php @@ -0,0 +1,54 @@ +getEmailAddress(); + } + + public function getAttributes(ContactInterface $contact): array + { + if (!$contact instanceof Adherent) { + throw new UnexpectedTypeException($contact, Adherent::class); + } + + return [ + AttributesEnum::FIELD_EMAIL => $contact->getEmailAddress(), + + AttributesEnum::FIELD_FIRST_NAME => $contact->getFirstName(), + AttributesEnum::FIELD_LAST_NAME => $contact->getLastName(), + + AttributesEnum::FIELD_BIRTHDATE => self::formatDate($contact->getBirthdate()), + AttributesEnum::FIELD_PHONE => self::formatPhone($contact->getPhone()), + + AttributesEnum::FIELD_CITY => $contact->getCityName(), + AttributesEnum::FIELD_POSTAL_CODE => $contact->getPostalCode(), + AttributesEnum::FIELD_COUNTRY => $contact->getCountry(), + + AttributesEnum::FIELD_SOURCE => $contact->getSource(), + AttributesEnum::FIELD_STATUS => $contact->getStatus(), + AttributesEnum::FIELD_CREATED_AT => self::formatDate($contact->getRegisteredAt()), + AttributesEnum::FIELD_UPDATED_AT => self::formatDate($contact->getUpdatedAt()), + AttributesEnum::FIELD_ACTIVATED_AT => self::formatDate($contact->getActivatedAt()), + + AttributesEnum::FIELD_SUBSCRIPTION_TYPES => implode(',', $contact->getSubscriptionTypeCodes()), + ]; + } +} diff --git a/src/SendInBlue/Manager/ContactManager.php b/src/SendInBlue/Manager/ContactManager.php new file mode 100644 index 00000000000..0ac90c39785 --- /dev/null +++ b/src/SendInBlue/Manager/ContactManager.php @@ -0,0 +1,59 @@ +getEmailAddress(); + } + + public function getAttributes(ContactInterface $contact): array + { + if (!$contact instanceof Contact) { + throw new UnexpectedTypeException($contact, Contact::class); + } + + return [ + AttributesEnum::FIELD_EMAIL => $contact->getEmailAddress(), + + AttributesEnum::FIELD_FIRST_NAME => $contact->getFirstName(), + AttributesEnum::FIELD_LAST_NAME => $contact->getLastName(), + + AttributesEnum::FIELD_BIRTHDATE => self::formatDate($contact->getBirthdate()), + AttributesEnum::FIELD_PHONE => self::formatPhone($contact->getPhone()), + + AttributesEnum::FIELD_CITY => $contact->getCityName(), + AttributesEnum::FIELD_POSTAL_CODE => $contact->getPostalCode(), + AttributesEnum::FIELD_COUNTRY => $contact->getCountry(), + + AttributesEnum::FIELD_SOURCE => $contact->getSource(), + AttributesEnum::FIELD_CREATED_AT => self::formatDate($contact->getCreatedAt()), + AttributesEnum::FIELD_UPDATED_AT => self::formatDate($contact->getUpdatedAt()), + + AttributesEnum::FIELD_ACTION_TERRAIN => \in_array(InterestEnum::ACTION_TERRAIN, $contact->getInterests(), true), + AttributesEnum::FIELD_CAMPAGNE_NUMERIQUE => \in_array(InterestEnum::CAMPAGNE_NUMERIQUE, $contact->getInterests(), true), + AttributesEnum::FIELD_PROCHES => \in_array(InterestEnum::PROCHES, $contact->getInterests(), true), + AttributesEnum::FIELD_INTERESTS_UPDATED_AT => $contact->getInterestsUpdatedAt(), + + AttributesEnum::FIELD_MAIL_CONTACT => $contact->isMailContact(), + AttributesEnum::FIELD_PHONE_CONTACT => $contact->isPhoneContact(), + ]; + } +} diff --git a/src/SendInBlue/Manager/ManagerInterface.php b/src/SendInBlue/Manager/ManagerInterface.php new file mode 100644 index 00000000000..7198b9ef91c --- /dev/null +++ b/src/SendInBlue/Manager/ManagerInterface.php @@ -0,0 +1,16 @@ +