Compare commits

..

5 Commits
1.0.1 ... 1.0.2

14 changed files with 383 additions and 75 deletions

View File

@ -4,7 +4,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased](https://git.d3data.de/D3Public/klicktipp-php-client/compare/1.0.0...rel_1.x) ## [Unreleased](https://git.d3data.de/D3Public/klicktipp-php-client/compare/1.0.2...rel_1.x)
## [1.0.2](https://git.d3data.de/D3Public/klicktipp-php-client/compare/1.0.1...1.0.2) - 2025-02-05
### Added
- reset subscription method
### Changed
- endpoint related task with missing endpoint instance throws an exception instead skipping it
### Fixed
- test for index null values in entities
## [1.0.1](https://git.d3data.de/D3Public/klicktipp-php-client/compare/1.0.0...1.0.1) - 2025-01-13
### Changed
- badges in README
## [1.0.0](https://git.d3data.de/D3Public/klicktipp-php-client/releases/tag/1.0.0) - 2025-01-09 ## [1.0.0](https://git.d3data.de/D3Public/klicktipp-php-client/releases/tag/1.0.0) - 2025-01-09
### Added ### Added

View File

@ -19,11 +19,14 @@ namespace D3\KlicktippPhpClient\Entities;
use D3\KlicktippPhpClient\Exceptions\CommunicationException; use D3\KlicktippPhpClient\Exceptions\CommunicationException;
use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException; use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException;
use D3\KlicktippPhpClient\Exceptions\MissingEndpointException;
use D3\KlicktippPhpClient\Resources\Account as AccountEndpoint; use D3\KlicktippPhpClient\Resources\Account as AccountEndpoint;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
class Account extends Entity class Account extends Entity
{ {
use EndpointTrait;
private ?AccountEndpoint $endpoint; private ?AccountEndpoint $endpoint;
public function __construct(array $elements = [], ?AccountEndpoint $endpoint = null) public function __construct(array $elements = [], ?AccountEndpoint $endpoint = null)
@ -193,9 +196,10 @@ class Account extends Entity
/** /**
* @return null|bool * @return null|bool
* @throws CommunicationException * @throws CommunicationException
* @throws MissingEndpointException
*/ */
public function persist(): ?bool public function persist(): ?bool
{ {
return $this->endpoint?->update(); return $this->getEndpoint()->update();
} }
} }

View File

@ -0,0 +1,36 @@
<?php
/**
* Copyright (c) D3 Data Development (Inh. Thomas Dartsch)
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
namespace D3\KlicktippPhpClient\Entities;
use Assert\Assert;
use D3\KlicktippPhpClient\Exceptions\MissingEndpointException;
use D3\KlicktippPhpClient\Resources\Model;
trait EndpointTrait
{
private function getEndpoint(): Model
{
Assert::lazy()
->setExceptionClass(MissingEndpointException::class)
->that($this->endpoint)
->isInstanceOf(Model::class)
->verifyNow();
return $this->endpoint;
}
}

View File

@ -18,10 +18,13 @@ declare(strict_types=1);
namespace D3\KlicktippPhpClient\Entities; namespace D3\KlicktippPhpClient\Entities;
use D3\KlicktippPhpClient\Exceptions\CommunicationException; use D3\KlicktippPhpClient\Exceptions\CommunicationException;
use D3\KlicktippPhpClient\Exceptions\MissingEndpointException;
use D3\KlicktippPhpClient\Resources\Field as FieldEndpoint; use D3\KlicktippPhpClient\Resources\Field as FieldEndpoint;
class Field extends Entity class Field extends Entity
{ {
use EndpointTrait;
private ?FieldEndpoint $endpoint; private ?FieldEndpoint $endpoint;
public function __construct(array $elements = [], ?FieldEndpoint $endpoint = null) public function __construct(array $elements = [], ?FieldEndpoint $endpoint = null)
@ -50,12 +53,15 @@ class Field extends Entity
/** /**
* @return null|bool * @return null|bool
* @throws CommunicationException * @throws CommunicationException
* @throws MissingEndpointException
*/ */
public function persist(): ?bool public function persist(): ?bool
{ {
return $this->endpoint?->update( return !is_null($this->getId()) ?
$this->getId(), $this->getEndpoint()->update(
$this->getName() $this->getId(),
); $this->getName() ?? ''
) :
null;
} }
} }

View File

@ -18,12 +18,15 @@ declare(strict_types=1);
namespace D3\KlicktippPhpClient\Entities; namespace D3\KlicktippPhpClient\Entities;
use D3\KlicktippPhpClient\Exceptions\CommunicationException; use D3\KlicktippPhpClient\Exceptions\CommunicationException;
use D3\KlicktippPhpClient\Exceptions\MissingEndpointException;
use D3\KlicktippPhpClient\Resources\Subscriber as SubscriberEndpoint; use D3\KlicktippPhpClient\Resources\Subscriber as SubscriberEndpoint;
use DateTime; use DateTime;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
class Subscriber extends Entity class Subscriber extends Entity
{ {
use EndpointTrait;
public const STATUS_SUBSCRIBED = 'subscribed'; public const STATUS_SUBSCRIBED = 'subscribed';
public const BOUNCE_NOTBOUNCED = 'Not Bounced'; public const BOUNCE_NOTBOUNCED = 'Not Bounced';
@ -175,7 +178,7 @@ class Subscriber extends Entity
// use persist method to send to Klicktipp // use persist method to send to Klicktipp
} }
protected function getFieldLongName(string $fieldId): ?string protected function getFieldLongName(string $fieldId): string
{ {
return str_starts_with($fieldId, 'field') ? trim($fieldId) : 'field'.trim($fieldId); return str_starts_with($fieldId, 'field') ? trim($fieldId) : 'field'.trim($fieldId);
} }
@ -193,15 +196,15 @@ class Subscriber extends Entity
public function clearTags(): void public function clearTags(): void
{ {
$tags = $this->getTags(); $tags = $this->getTags();
$tags->clear(); $tags?->clear();
$this->set(SubscriberEndpoint::TAGS, $tags->toArray()); $this->set(SubscriberEndpoint::TAGS, $tags?->toArray());
// use persist method to send to Klicktipp // use persist method to send to Klicktipp
} }
public function addTag(string $tagId): void public function addTag(string $tagId): void
{ {
$tags = $this->getTags(); $tags = $this->getTags() ?: new ArrayCollection();
$tags->add($tagId); $tags->add($tagId);
$this->set(SubscriberEndpoint::TAGS, $tags->toArray()); $this->set(SubscriberEndpoint::TAGS, $tags->toArray());
@ -211,8 +214,8 @@ class Subscriber extends Entity
public function removeTag(string $tagId): void public function removeTag(string $tagId): void
{ {
$tags = $this->getTags(); $tags = $this->getTags();
$tags->removeElement($tagId); $tags?->removeElement($tagId);
$this->set(SubscriberEndpoint::TAGS, $tags->toArray()); $this->set(SubscriberEndpoint::TAGS, $tags?->toArray());
// use persist method to send to Klicktipp // use persist method to send to Klicktipp
} }
@ -232,7 +235,7 @@ class Subscriber extends Entity
public function getManualTagTime(string $tagId): ?DateTime public function getManualTagTime(string $tagId): ?DateTime
{ {
return $this->getDateTimeFromValue($this->getManualTags()->get($tagId)); return $this->getDateTimeFromValue($this->getManualTags()?->get($tagId));
} }
public function getSmartTags(): ?ArrayCollection public function getSmartTags(): ?ArrayCollection
@ -314,42 +317,81 @@ class Subscriber extends Entity
/** /**
* @return null|bool * @return null|bool
* @throws CommunicationException * @throws CommunicationException
* @throws MissingEndpointException
*/ */
public function persist(): ?bool public function persist(): ?bool
{ {
$return = $this->endpoint?->update( if (!is_null($this->getId())) {
$this->getId(), $return = $this->getEndpoint()->update(
$this->getFields()->toArray(), $this->getId(),
$this->getEmailAddress(), $this->getFields()->toArray(),
$this->getSmsPhone() $this->getEmailAddress() ?? '',
); $this->getSmsPhone() ?? ''
);
$this->persistTags(); $this->persistTags();
return $return; return $return;
}
return null;
} }
/** /**
* @throws CommunicationException * @throws CommunicationException
* @throws MissingEndpointException
*/ */
protected function persistTags(): void protected function persistTags(): void
{ {
if (!$this->endpoint instanceof SubscriberEndpoint) { $currentTags = $this->getEndpoint()->getEntity($this->getId() ?? '')->getTags();
return;
}
$currentTags = $this->endpoint->getEntity($this->getId())->getTags(); $removeTags = array_diff(
$currentTags?->toArray() ?? [],
$this->getTags()?->toArray() ?? []
);
$removeTags = array_diff($currentTags->toArray(), $this->getTags()->toArray());
if (count($removeTags)) { if (count($removeTags)) {
foreach ($removeTags as $removeTag) { foreach ($removeTags as $removeTag) {
$this->endpoint->untag($this->getEmailAddress(), $removeTag); if (!is_null($this->getEmailAddress())) {
$this->getEndpoint()->untag($this->getEmailAddress(), $removeTag);
}
} }
} }
$addTags = array_diff($this->getTags()->toArray(), $currentTags->toArray()); $addTags = array_diff(
$this->getTags()?->toArray() ?? [],
$currentTags?->toArray() ?? []
);
if (count($addTags)) { if (count($addTags)) {
$this->endpoint->tag($this->getEmailAddress(), $addTags); if (!is_null($this->getEmailAddress())) {
$this->getEndpoint()->tag($this->getEmailAddress(), $addTags);
}
}
}
/**
* @param string $listId
* @param string|null $tagId
* @param array|null $fields
* @param string|null $smsNumber
*
* @return void
* @throws CommunicationException
*/
public function resubscribe(
string $listId,
?string $tagId = null,
?array $fields = null,
?string $smsNumber = null
): void {
if (!$this->isSubscribed()) {
$this->getEndpoint()->subscribe(
$this->getEmailAddress(),
$listId,
$tagId,
$fields,
$smsNumber
);
} }
} }

View File

@ -18,10 +18,13 @@ declare(strict_types=1);
namespace D3\KlicktippPhpClient\Entities; namespace D3\KlicktippPhpClient\Entities;
use D3\KlicktippPhpClient\Exceptions\CommunicationException; use D3\KlicktippPhpClient\Exceptions\CommunicationException;
use D3\KlicktippPhpClient\Exceptions\MissingEndpointException;
use D3\KlicktippPhpClient\Resources\SubscriptionProcess; use D3\KlicktippPhpClient\Resources\SubscriptionProcess;
class Subscription extends Entity class Subscription extends Entity
{ {
use EndpointTrait;
private ?SubscriptionProcess $endpoint; private ?SubscriptionProcess $endpoint;
public function __construct(array $elements = [], ?SubscriptionProcess $endpoint = null) public function __construct(array $elements = [], ?SubscriptionProcess $endpoint = null)
@ -78,12 +81,15 @@ class Subscription extends Entity
/** /**
* @return null|bool * @return null|bool
* @throws CommunicationException * @throws CommunicationException
* @throws MissingEndpointException
*/ */
public function persist(): ?bool public function persist(): ?bool
{ {
return $this->endpoint?->update( return !is_null($this->getListId()) ?
$this->getListId(), $this->getEndpoint()->update(
$this->getName() $this->getListId(),
); $this->getName() ?? ''
) :
null;
} }
} }

View File

@ -18,10 +18,13 @@ declare(strict_types=1);
namespace D3\KlicktippPhpClient\Entities; namespace D3\KlicktippPhpClient\Entities;
use D3\KlicktippPhpClient\Exceptions\CommunicationException; use D3\KlicktippPhpClient\Exceptions\CommunicationException;
use D3\KlicktippPhpClient\Exceptions\MissingEndpointException;
use D3\KlicktippPhpClient\Resources\Tag as TagEndpoint; use D3\KlicktippPhpClient\Resources\Tag as TagEndpoint;
class Tag extends Entity class Tag extends Entity
{ {
use EndpointTrait;
private ?TagEndpoint $endpoint; private ?TagEndpoint $endpoint;
public function __construct(array $elements = [], ?TagEndpoint $endpoint = null) public function __construct(array $elements = [], ?TagEndpoint $endpoint = null)
@ -62,13 +65,16 @@ class Tag extends Entity
/** /**
* @return null|bool * @return null|bool
* @throws CommunicationException * @throws CommunicationException
* @throws MissingEndpointException
*/ */
public function persist(): ?bool public function persist(): ?bool
{ {
return $this->endpoint?->update( return !is_null($this->getId()) ?
$this->getId(), $this->getEndpoint()->update(
$this->getName(), $this->getId(),
$this->getText() $this->getName() ?? '',
); $this->getText() ?? ''
) :
null;
} }
} }

View File

@ -0,0 +1,29 @@
<?php
/**
* Copyright (c) D3 Data Development (Inh. Thomas Dartsch)
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
namespace D3\KlicktippPhpClient\Exceptions;
use Assert\LazyAssertionException;
class MissingEndpointException extends LazyAssertionException implements KlicktippExceptionInterface
{
public function __construct($message, array $errors)
{
unset($message);
parent::__construct('required endpoint for this action missing', $errors);
}
}

View File

@ -19,6 +19,7 @@ namespace D3\KlicktippPhpClient\tests\unit\Entities;
use D3\KlicktippPhpClient\Entities\Account; use D3\KlicktippPhpClient\Entities\Account;
use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException; use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException;
use D3\KlicktippPhpClient\Exceptions\MissingEndpointException;
use D3\KlicktippPhpClient\Resources\Account as AccountEndpoint; use D3\KlicktippPhpClient\Resources\Account as AccountEndpoint;
use D3\KlicktippPhpClient\tests\TestCase; use D3\KlicktippPhpClient\tests\TestCase;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
@ -526,6 +527,10 @@ class AccountTest extends TestCase
$sut = new Account([AccountEndpoint::UID => 'foo'], $endpointSet ? $endpointMock : null); $sut = new Account([AccountEndpoint::UID => 'foo'], $endpointSet ? $endpointMock : null);
if (!$endpointSet) {
$this->expectException(MissingEndpointException::class);
}
$this->assertSame( $this->assertSame(
$expectedReturn, $expectedReturn,
$this->callMethod( $this->callMethod(

View File

@ -19,6 +19,7 @@ namespace D3\KlicktippPhpClient\tests\unit\Entities;
use D3\KlicktippPhpClient\Entities\Field; use D3\KlicktippPhpClient\Entities\Field;
use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException; use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException;
use D3\KlicktippPhpClient\Exceptions\MissingEndpointException;
use D3\KlicktippPhpClient\Resources\Field as FieldEndpoint; use D3\KlicktippPhpClient\Resources\Field as FieldEndpoint;
use D3\KlicktippPhpClient\tests\TestCase; use D3\KlicktippPhpClient\tests\TestCase;
use Generator; use Generator;
@ -184,6 +185,10 @@ class FieldTest extends TestCase
$endpointSet ? $endpointMock : null $endpointSet ? $endpointMock : null
); );
if (!$endpointSet) {
$this->expectException(MissingEndpointException::class);
}
$this->assertSame( $this->assertSame(
$expectedReturn, $expectedReturn,
$this->callMethod( $this->callMethod(

View File

@ -19,6 +19,7 @@ namespace D3\KlicktippPhpClient\tests\unit\Entities;
use D3\KlicktippPhpClient\Entities\Subscriber; use D3\KlicktippPhpClient\Entities\Subscriber;
use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException; use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException;
use D3\KlicktippPhpClient\Exceptions\MissingEndpointException;
use D3\KlicktippPhpClient\Resources\Subscriber as SubscriberEndpoint; use D3\KlicktippPhpClient\Resources\Subscriber as SubscriberEndpoint;
use D3\KlicktippPhpClient\tests\TestCase; use D3\KlicktippPhpClient\tests\TestCase;
use DateTime; use DateTime;
@ -706,12 +707,11 @@ class SubscriberTest extends TestCase
* @covers \D3\KlicktippPhpClient\Entities\Subscriber::isTagSet * @covers \D3\KlicktippPhpClient\Entities\Subscriber::isTagSet
* @dataProvider isTagSetDataProvider * @dataProvider isTagSetDataProvider
*/ */
public function testIsTagSet(string $searchTagId, bool $expected): void public function testIsTagSet(?array $currentTags, string $searchTagId, bool $expected): void
{ {
$tagList = new ArrayCollection([ $tagList = is_null($currentTags) ?
"12494453", null :
"12494463", new ArrayCollection($currentTags);
]);
$sut = $this->getMockBuilder(Subscriber::class) $sut = $this->getMockBuilder(Subscriber::class)
->onlyMethods(['getTags']) ->onlyMethods(['getTags'])
@ -730,8 +730,9 @@ class SubscriberTest extends TestCase
public static function isTagSetDataProvider(): Generator public static function isTagSetDataProvider(): Generator
{ {
yield 'existing tag' => ['12494463', true]; yield 'existing tag' => [["12494453", "12494463"], '12494463', true];
yield 'missing tag' => ['12495463', false]; yield 'missing tag' => [["12494453", "12494463"], '12495463', false];
yield 'null tag' => [null, '12495463', false];
} }
/** /**
@ -739,15 +740,27 @@ class SubscriberTest extends TestCase
* @return void * @return void
* @covers \D3\KlicktippPhpClient\Entities\Subscriber::clearTags * @covers \D3\KlicktippPhpClient\Entities\Subscriber::clearTags
* @throws ReflectionException * @throws ReflectionException
* @dataProvider clearTagsDataProvider
*/ */
public function testClearTags(): void public function testClearTags(?array $currentTagList, ?array $expectedTags): void
{ {
$entityMock = new Subscriber([SubscriberEndpoint::TAGS => $currentTagList]);
$this->callMethod( $this->callMethod(
$this->entity, $entityMock,
'clearTags' 'clearTags'
); );
$this->assertCount(0, $this->callMethod($this->entity, 'getTags')); is_null($expectedTags) ?
$this->assertNull($this->callMethod($entityMock, 'getTags')) :
$this->assertEquals(new ArrayCollection($expectedTags), $this->callMethod($entityMock, 'getTags'));
}
public static function clearTagsDataProvider(): Generator
{
yield 'tag list exists' => [["12494453","12494463"], []];
yield 'tag list empty' => [[], []];
yield 'tag list null' => [null, null];
} }
/** /**
@ -755,36 +768,56 @@ class SubscriberTest extends TestCase
* @return void * @return void
* @covers \D3\KlicktippPhpClient\Entities\Subscriber::addTag * @covers \D3\KlicktippPhpClient\Entities\Subscriber::addTag
* @throws ReflectionException * @throws ReflectionException
* @dataProvider addTagDataProvider
*/ */
public function testAddTag(): void public function testAddTag(?array $currentTagList, ?array $expectedTagList): void
{ {
$entityMock = new Subscriber([SubscriberEndpoint::TAGS => $currentTagList]);
$this->callMethod( $this->callMethod(
$this->entity, $entityMock,
'addTag', 'addTag',
['78546214'] ['78546214']
); );
$this->assertCount(3, $this->callMethod($this->entity, 'getTags')); is_null($expectedTagList) ?
$this->assertContains('78546214', $this->callMethod($this->entity, 'getTags')); $this->assertNull($this->callMethod($entityMock, 'getTags')) :
$this->assertEquals(new ArrayCollection($expectedTagList), $this->callMethod($entityMock, 'getTags'));
}
public static function addTagDataProvider(): Generator
{
yield 'tag list exists' => [["12494453","12494463"], ["12494453","12494463", "78546214"]];
yield 'tag list empty' => [[], ["78546214"]];
yield 'tag list null' => [null, ["78546214"]];
} }
/** /**
* @test * @test
* @return void
* @covers \D3\KlicktippPhpClient\Entities\Subscriber::removeTag
* @throws ReflectionException * @throws ReflectionException
* @covers \D3\KlicktippPhpClient\Entities\Subscriber::removeTag
* @dataProvider removeTagDataProvider
*/ */
public function testRemoveTag(): void public function testRemoveTag(?array $currentTagList, ?array $expectedTags): void
{ {
$entityMock = new Subscriber([SubscriberEndpoint::TAGS => $currentTagList]);
$this->callMethod( $this->callMethod(
$this->entity, $entityMock,
'removeTag', 'removeTag',
['12494453'] ['12494453']
); );
$this->assertCount(1, $this->callMethod($this->entity, 'getTags')); is_null($expectedTags) ?
$this->assertContains('12494463', $this->callMethod($this->entity, 'getTags')); $this->assertNull($this->callMethod($entityMock, 'getTags')) :
$this->assertNotContains('12494453', $this->callMethod($this->entity, 'getTags')); $this->assertEquals(new ArrayCollection($expectedTags), $this->callMethod($entityMock, 'getTags'));
}
public static function removeTagDataProvider(): Generator
{
yield 'tag list exists' => [["12494453","12494463"], [1 => "12494463"]];
yield 'tag list empty' => [[], []];
yield 'tag list null' => [null, null];
} }
/** /**
@ -795,7 +828,9 @@ class SubscriberTest extends TestCase
*/ */
public function testPersist( public function testPersist(
bool $endpointSet, bool $endpointSet,
?string $currentId,
InvokedCount $endpointInvocation, InvokedCount $endpointInvocation,
InvokedCount $persistTagsInvocation,
?bool $expectedReturn ?bool $expectedReturn
): void { ): void {
$endpointMock = $this->getMockBuilder(SubscriberEndpoint::class) $endpointMock = $this->getMockBuilder(SubscriberEndpoint::class)
@ -805,10 +840,14 @@ class SubscriberTest extends TestCase
$endpointMock->expects($endpointInvocation)->method('update')->willReturn(true); $endpointMock->expects($endpointInvocation)->method('update')->willReturn(true);
$sut = $this->getMockBuilder(Subscriber::class) $sut = $this->getMockBuilder(Subscriber::class)
->setConstructorArgs([[SubscriberEndpoint::ID => 'foo'], $endpointSet ? $endpointMock : null]) ->setConstructorArgs([[SubscriberEndpoint::ID => $currentId], $endpointSet ? $endpointMock : null])
->onlyMethods(['persistTags']) ->onlyMethods(['persistTags'])
->getMock(); ->getMock();
$sut->expects($this->once())->method('persistTags'); $sut->expects($persistTagsInvocation)->method('persistTags');
if (!$endpointSet) {
$this->expectException(MissingEndpointException::class);
}
$this->assertSame( $this->assertSame(
$expectedReturn, $expectedReturn,
@ -821,8 +860,9 @@ class SubscriberTest extends TestCase
public static function persistDataProvider(): Generator public static function persistDataProvider(): Generator
{ {
yield 'has endpoint' => [true, self::once(), true]; yield 'has endpoint' => [true, 'fixture', self::once(), self::once(), true];
yield 'has no endpoint' => [false, self::never(), null]; yield 'has no endpoint' => [false, 'fixture', self::never(), self::never(), null];
yield 'has endpoint, no id' => [true, null, self::never(), self::never(), null];
} }
/** /**
@ -834,6 +874,7 @@ class SubscriberTest extends TestCase
public function testPersistTags( public function testPersistTags(
bool $endpointSet, bool $endpointSet,
InvokedCount $endpointInvocation, InvokedCount $endpointInvocation,
?array $currentTagList,
?array $newTagList, ?array $newTagList,
InvokedCount $removeTagInvocation, InvokedCount $removeTagInvocation,
InvokedCount $setTagInvocation InvokedCount $setTagInvocation
@ -842,10 +883,9 @@ class SubscriberTest extends TestCase
->disableOriginalConstructor() ->disableOriginalConstructor()
->onlyMethods(['getTags']) ->onlyMethods(['getTags'])
->getMock(); ->getMock();
$entityMock->method('getTags')->willReturn(new ArrayCollection([ $entityMock->method('getTags')->willReturn(
"12494453", is_null($currentTagList) ? null : new ArrayCollection($currentTagList)
"12494463", );
]));
$endpointMock = $this->getMockBuilder(SubscriberEndpoint::class) $endpointMock = $this->getMockBuilder(SubscriberEndpoint::class)
->disableOriginalConstructor() ->disableOriginalConstructor()
@ -860,6 +900,10 @@ class SubscriberTest extends TestCase
$sut->set('tags', $newTagList); $sut->set('tags', $newTagList);
} }
if (!$endpointSet) {
$this->expectException(MissingEndpointException::class);
}
$this->callMethod( $this->callMethod(
$sut, $sut,
'persistTags' 'persistTags'
@ -868,10 +912,11 @@ class SubscriberTest extends TestCase
public static function persistTagsDataProvider(): Generator public static function persistTagsDataProvider(): Generator
{ {
yield 'has endpoint, tag removed' => [true, self::once(), ["12494453"], self::once(), self::never()]; yield 'has endpoint, tag removed' => [true, self::once(), ["12494453", "12494463"], ["12494453"], self::once(), self::never()];
yield 'has endpoint, tag added' => [true, self::once(), ["12494453","12494463","12494464"], self::never(), self::once()]; yield 'has endpoint, tag added' => [true, self::once(), ["12494453", "12494463"], ["12494453","12494463","12494464"], self::never(), self::once()];
yield 'has endpoint, taglist equals' => [true, self::once(), ["12494453","12494463"], self::never(), self::never()]; yield 'has endpoint, taglist equals' => [true, self::once(), ["12494453", "12494463"], ["12494453","12494463"], self::never(), self::never()];
yield 'has no endpoint' => [false, self::never(), null, self::never(), self::never()]; yield 'has no endpoint' => [false, self::never(), ["12494453", "12494463"], null, self::never(), self::never()];
yield 'has endpoint, taglist null' => [true, self::once(), null, null, self::never(), self::never()];
} }
/** /**
@ -942,4 +987,48 @@ class SubscriberTest extends TestCase
yield ['getStartedCampaignTime', 'getStartedCampaigns']; yield ['getStartedCampaignTime', 'getStartedCampaigns'];
yield ['getFinishedCampaignTime', 'getFinishedCampaigns']; yield ['getFinishedCampaignTime', 'getFinishedCampaigns'];
} }
/**
* @test
* @throws ReflectionException
* @covers \D3\KlicktippPhpClient\Entities\Subscriber::resubscribe
* @covers \D3\KlicktippPhpClient\Entities\Subscriber::getEndpoint
* @dataProvider resubscribeDataProvider
*/
public function testReSubscribe(
bool $endpointSet,
InvokedCount $subscribeExpections,
bool $isSubscribed
): void {
$endpointMock = $this->getMockBuilder(SubscriberEndpoint::class)
->disableOriginalConstructor()
->onlyMethods(['subscribe'])
->getMock();
$endpointMock->expects($subscribeExpections)->method('subscribe');
$sut = $this->getMockBuilder(Subscriber::class)
->setConstructorArgs([[], $endpointSet ? $endpointMock : null])
->onlyMethods(['isSubscribed', 'getEmailAddress'])
->getMock();
$sut->method('isSubscribed')->willReturn($isSubscribed);
$sut->method('getEmailAddress')->willReturn('mail@mydomain.tld');
if (!$endpointSet && !$isSubscribed) {
$this->expectException(MissingEndpointException::class);
}
$this->callMethod(
$sut,
'resubscribe',
['listId', 'tagid']
);
}
public static function resubscribeDataProvider(): Generator
{
yield 'already subscribed, has endpoint' => [true, self::never(), true];
yield 'unsubscribed, has endpoint' => [true, self::once(), false];
yield 'already subscribed, no endpoint' => [false, self::never(), true];
yield 'unsubscribed, no endpoint' => [false, self::never(), false];
}
} }

View File

@ -19,6 +19,7 @@ namespace D3\KlicktippPhpClient\tests\unit\Entities;
use D3\KlicktippPhpClient\Entities\Subscription; use D3\KlicktippPhpClient\Entities\Subscription;
use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException; use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException;
use D3\KlicktippPhpClient\Exceptions\MissingEndpointException;
use D3\KlicktippPhpClient\Resources\SubscriptionProcess as SubscriptionEndpoint; use D3\KlicktippPhpClient\Resources\SubscriptionProcess as SubscriptionEndpoint;
use D3\KlicktippPhpClient\tests\TestCase; use D3\KlicktippPhpClient\tests\TestCase;
use Generator; use Generator;
@ -205,6 +206,7 @@ class SubscriptionTest extends TestCase
*/ */
public function testPersist( public function testPersist(
bool $endpointSet, bool $endpointSet,
?string $id,
InvokedCount $endpointInvocation, InvokedCount $endpointInvocation,
?bool $expectedReturn ?bool $expectedReturn
): void { ): void {
@ -213,15 +215,19 @@ class SubscriptionTest extends TestCase
->onlyMethods(['update']) ->onlyMethods(['update'])
->getMock(); ->getMock();
$endpointMock->expects($endpointInvocation)->method('update')->with( $endpointMock->expects($endpointInvocation)->method('update')->with(
$this->identicalTo('foo'), $this->identicalTo($id),
$this->identicalTo('bar'), $this->identicalTo('bar'),
)->willReturn(true); )->willReturn(true);
$sut = new Subscription( $sut = new Subscription(
[SubscriptionEndpoint::LISTID => 'foo', SubscriptionEndpoint::NAME => 'bar'], [SubscriptionEndpoint::LISTID => $id, SubscriptionEndpoint::NAME => 'bar'],
$endpointSet ? $endpointMock : null $endpointSet ? $endpointMock : null
); );
if (!$endpointSet) {
$this->expectException(MissingEndpointException::class);
}
$this->assertSame( $this->assertSame(
$expectedReturn, $expectedReturn,
$this->callMethod( $this->callMethod(
@ -233,7 +239,8 @@ class SubscriptionTest extends TestCase
public static function persistDataProvider(): Generator public static function persistDataProvider(): Generator
{ {
yield 'has endpoint' => [true, self::once(), true]; yield 'has endpoint' => [true, 'fixture', self::once(), true];
yield 'has no endpoint' => [false, self::never(), null]; yield 'has no endpoint' => [false, 'fixture', self::never(), null];
yield 'has endpoint, no id' => [true, null, self::never(), null];
} }
} }

View File

@ -19,6 +19,7 @@ namespace D3\KlicktippPhpClient\tests\unit\Entities;
use D3\KlicktippPhpClient\Entities\Tag; use D3\KlicktippPhpClient\Entities\Tag;
use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException; use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException;
use D3\KlicktippPhpClient\Exceptions\MissingEndpointException;
use D3\KlicktippPhpClient\Resources\Tag as TagEndpoint; use D3\KlicktippPhpClient\Resources\Tag as TagEndpoint;
use D3\KlicktippPhpClient\tests\TestCase; use D3\KlicktippPhpClient\tests\TestCase;
use Generator; use Generator;
@ -198,6 +199,10 @@ class TagTest extends TestCase
$endpointSet ? $endpointMock : null $endpointSet ? $endpointMock : null
); );
if (!$endpointSet) {
$this->expectException(MissingEndpointException::class);
}
$this->assertSame( $this->assertSame(
$expectedReturn, $expectedReturn,
$this->callMethod( $this->callMethod(

View File

@ -0,0 +1,54 @@
<?php
/**
* Copyright (c) D3 Data Development (Inh. Thomas Dartsch)
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
namespace D3\KlicktippPhpClient\tests\unit\Exceptions;
use D3\KlicktippPhpClient\Exceptions\CommunicationException;
use D3\KlicktippPhpClient\Exceptions\MissingEndpointException;
use D3\KlicktippPhpClient\tests\TestCase;
use ReflectionException;
/**
* @covers \D3\KlicktippPhpClient\Exceptions\MissingEndpointException
*/
class MissingEndpointExceptionTest extends TestCase
{
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\KlicktippPhpClient\Exceptions\MissingEndpointException::__construct
*/
public function testConstructor(): void
{
/** @var MissingEndpointException $sutMock */
$sutMock = $this->getMockBuilder(MissingEndpointException::class)
->disableOriginalConstructor()
->getMock();
$this->callMethod(
$sutMock,
'__construct',
['myMessage', []]
);
$this->assertMatchesRegularExpression(
'/.*?endpoint.*?missing.*/i',
$sutMock->getMessage()
);
}
}