Skip to content

Commit

Permalink
Fix update existing contact via sending blue (#348)
Browse files Browse the repository at this point in the history
* Fix update existing contact via sending blue

* Add update of sendin blue contact

* Add some test cases
  • Loading branch information
alexander-schranz committed Feb 16, 2023
1 parent 7de5d2a commit d519522
Show file tree
Hide file tree
Showing 4 changed files with 296 additions and 18 deletions.
4 changes: 2 additions & 2 deletions Entity/FormField.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ class FormField
/**
* @var string
*/
private $width;
private $width = 'full';

/**
* @var bool
*/
private $required;
private $required = false;

/**
* @var null|int
Expand Down
79 changes: 64 additions & 15 deletions Event/SendinblueListSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@

namespace Sulu\Bundle\FormBundle\Event;

use GuzzleHttp\ClientInterface;
use SendinBlue\Client\Api\ContactsApi;
use SendinBlue\Client\ApiException;
use SendinBlue\Client\Configuration;
use SendinBlue\Client\Model\CreateDoiContact;
use SendinBlue\Client\Model\UpdateContact;
use Sulu\Bundle\FormBundle\Entity\Dynamic;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
Expand All @@ -35,8 +38,11 @@ class SendinblueListSubscriber implements EventSubscriberInterface
*/
private $contactsApi;

public function __construct(RequestStack $requestStack, ?string $apiKey)
{
public function __construct(
RequestStack $requestStack,
?string $apiKey,
?ClientInterface $client = null
) {
$this->requestStack = $requestStack;

if (!$apiKey) {
Expand All @@ -46,7 +52,7 @@ public function __construct(RequestStack $requestStack, ?string $apiKey)
$config = new Configuration();
$config->setApiKey('api-key', $apiKey);

$this->contactsApi = new ContactsApi(null, $config);
$this->contactsApi = new ContactsApi($client, $config);
}

public static function getSubscribedEvents()
Expand Down Expand Up @@ -89,7 +95,9 @@ public function listSubscribe(FormSavePostEvent $event): void
} elseif ('email' === $field['type'] && !$email) {
$email = $field['value'];
} elseif ('sendinblue' == $field['type'] && $field['value']) {
/** @var string|int|null $listId */
$mailTemplateId = $field['options']['mailTemplateId'] ?? null;
/** @var int|null $listId */
$listId = $field['options']['listId'] ?? null;

if (!$mailTemplateId || !$listId) {
Expand All @@ -100,21 +108,62 @@ public function listSubscribe(FormSavePostEvent $event): void
}
}

if ($email && \count($listIdsByMailTemplate) > 0) {
foreach ($listIdsByMailTemplate as $mailTemplateId => $listIds) {
$createDoiContact = new CreateDoiContact([
'email' => $email,
'templateId' => $mailTemplateId,
'includeListIds' => $listIds,
'redirectionUrl' => $redirectionUrl,
'attributes' => [
/** @var string $email */
if (!$email || 0 === \count($listIdsByMailTemplate)) {
return;
}

$contact = null;
try {
$contact = $this->contactsApi->getContactInfo($email);
} catch (ApiException $e) {
if (404 !== $e->getCode()) {
throw $e;
}
// Contact does not exist, ignore the exception
}

if (null !== $contact) {
$updateContact = new UpdateContact();

$updateContact->setAttributes(
(object) \array_replace(
(array) $contact->getAttributes(),
[
'FIRST_NAME' => $firstName,
'LAST_NAME' => $firstName,
],
]);
'LAST_NAME' => $lastName,
]
)
);

$this->contactsApi->createDoiContact($createDoiContact);
/** @var int[] $collectedListIds */
$collectedListIds = $contact->getListIds();
foreach ($listIdsByMailTemplate as $mailTemplateId => $listIds) {
$collectedListIds = \array_merge($collectedListIds, $listIds);
}

$collectedListIds = \array_unique($collectedListIds);

$updateContact->setListIds($collectedListIds);

$this->contactsApi->updateContact($email, $updateContact);

return;
}

foreach ($listIdsByMailTemplate as $mailTemplateId => $listIds) {
$createDoiContact = new CreateDoiContact([
'email' => $email,
'templateId' => $mailTemplateId,
'includeListIds' => $listIds,
'redirectionUrl' => $redirectionUrl,
'attributes' => [
'FIRST_NAME' => $firstName,
'LAST_NAME' => $lastName,
],
]);

$this->contactsApi->createDoiContact($createDoiContact);
}
}
}
228 changes: 228 additions & 0 deletions Tests/Unit/Event/SendinblueListSubscriberTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
<?php

/*
* This file is part of Sulu.
*
* (c) Sulu GmbH
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Sulu\Bundle\FormBundle\Tests\Unit\Event;

use GuzzleHttp\ClientInterface;
use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
use Psr\Http\Message\RequestInterface;
use SendinBlue\Client\ApiException;
use Sulu\Bundle\FormBundle\Configuration\FormConfiguration;
use Sulu\Bundle\FormBundle\Entity\Dynamic;
use Sulu\Bundle\FormBundle\Entity\Form;
use Sulu\Bundle\FormBundle\Entity\FormField;
use Sulu\Bundle\FormBundle\Entity\FormTranslation;
use Sulu\Bundle\FormBundle\Event\FormSavePostEvent;
use Sulu\Bundle\FormBundle\Event\SendinblueListSubscriber;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;

class SendinblueListSubscriberTest extends TestCase
{
/**
* @var RequestStack
*/
private $requestStack;

/**
* @var ObjectProphecy<ClientInterface>
*/
private $client;

/**
* @var SendinblueListSubscriber
*/
private $sendinblueListSubscriber;

public function setUp(): void
{
$this->requestStack = new RequestStack();
$this->client = $this->prophesize(ClientInterface::class);

$this->sendinblueListSubscriber = new SendinblueListSubscriber(
$this->requestStack,
'SOME_KEY',
$this->client->reveal()
);
}

public function testGetSubscribedEvents(): void
{
$this->assertSame(
[
'sulu_form.handler.saved' => 'listSubscribe',
],
SendinblueListSubscriber::getSubscribedEvents()
);
}

public function testlistSubscribeNotExist(): void
{
$this->requestStack->push(Request::create('http://localhost/', 'POST'));
$event = $this->createFormSavePostEvent();

$self = $this;
$this->client->send(Argument::cetera())->will(function($args) use ($self) {
/** @var RequestInterface $request */
$request = $args[0];

if ('https://api.sendinblue.com/v3/contacts/john.doe%40example.org' === $request->getUri()->__toString()) {
$self->assertSame('GET', $request->getMethod());

throw new ApiException('', 404);
}

if ('https://api.sendinblue.com/v3/contacts/doubleOptinConfirmation' === $request->getUri()->__toString()) {
$self->assertSame('POST', $request->getMethod());

$json = \json_decode($request->getBody()->getContents(), true);

$self->assertSame([
'email' => 'john.doe@example.org',
'attributes' => [
'FIRST_NAME' => 'John',
'LAST_NAME' => 'Doe',
],
'includeListIds' => ['789'],
'templateId' => 456,
'redirectionUrl' => 'http://localhost?subscribe=true',
], $json);

return new Response();
}

throw new \RuntimeException('Unexpected request: ' . $request->getUri()->__toString());
})
->shouldBeCalledTimes(2);

// act
$this->sendinblueListSubscriber->listSubscribe($event);

$this->assertTrue(true);
}

public function testlistSubscribeAlreadyExist(): void
{
$this->requestStack->push(Request::create('http://localhost/', 'POST'));
$event = $this->createFormSavePostEvent();

$self = $this;
$this->client->send(Argument::cetera())->will(function($args) use ($self) {
/** @var RequestInterface $request */
$request = $args[0];

if ('https://api.sendinblue.com/v3/contacts/john.doe%40example.org' === $request->getUri()->__toString()
&& 'GET' === $request->getMethod()
) {
return new Response(200, ['Content-Type' => 'application/json'], \json_encode([
'id' => 123,
'email' => 'john.doe@example.org',
'attributes' => [],
'listIds' => [],
]));
}

if ('https://api.sendinblue.com/v3/contacts/john.doe%40example.org' === $request->getUri()->__toString()
&& 'PUT' === $request->getMethod()
) {
$json = \json_decode($request->getBody()->getContents(), true);

$self->assertSame([
'attributes' => [
'FIRST_NAME' => 'John',
'LAST_NAME' => 'Doe',
],
'listIds' => ['789'],
], $json);

return new Response();
}

throw new \RuntimeException('Unexpected request (' . $request->getMethod() . '): ' . $request->getUri()->__toString());
})
->shouldBeCalledTimes(2);

// act
$this->sendinblueListSubscriber->listSubscribe($event);

$this->assertTrue(true);
}

private function createFormSavePostEvent(): FormSavePostEvent
{
$symfonyForm = $this->prophesize(FormInterface::class);
$formConfiguration = new FormConfiguration('en');
$form = new Form();
$form->setDefaultLocale('en');
$formTranslation = new FormTranslation();
$formTranslation->setLocale('en');
$formTranslation->setTitle('Form');
$form->addTranslation($formTranslation);

$fields = [
[
'type' => 'firstName',
'required' => true,
],
[
'type' => 'lastName',
'required' => true,
],
[
'type' => 'email',
'required' => true,
],
[
'type' => 'sendinblue',
'options' => [
'mailTemplateId' => '456',
'listId' => '789',
],
],
];

foreach ($fields as $key => $field) {
$formField = new FormField();
$formField->setForm($form);
$formField->setDefaultLocale('en');
$formField->setType($field['type']);
$formField->setOrder($key);
$formField->setKey($field['type']);

$formFieldTranslation = $formField->getTranslation('en', true);
$formFieldTranslation->setTitle(\ucfirst($field['type']));
$formFieldTranslation->setOptions($field['options'] ?? []);

$form->addField($formField);
}

$dynamic = new Dynamic(
'page',
'123',
'en',
$form,
[
'firstName' => 'John',
'lastName' => 'Doe',
'email' => 'john.doe@example.org',
'sendinblue' => true,
]
);

$symfonyForm->getData()->willReturn($dynamic);

return new FormSavePostEvent($symfonyForm->reveal(), $formConfiguration);
}
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@
},
"sort-packages": true,
"allow-plugins": {
"composer/package-versions-deprecated": true
"composer/package-versions-deprecated": true,
"php-http/discovery": true
}
}
}

0 comments on commit d519522

Please sign in to comment.