initial commit

This commit is contained in:
2025-07-12 20:27:07 +02:00
commit 29b2ddd1a5
25 changed files with 1671 additions and 0 deletions

18
.editorconfig Normal file
View File

@@ -0,0 +1,18 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.php]
indent_size = 4
[composer.*]
indent_size = 4

145
.gitignore vendored Normal file
View File

@@ -0,0 +1,145 @@
vendor/autoload.php
vendor/composer/autoload_classmap.php
vendor/composer/autoload_files.php
vendor/composer/autoload_namespaces.php
vendor/composer/autoload_psr4.php
vendor/composer/autoload_real.php
vendor/composer/autoload_static.php
vendor/composer/ClassLoader.php
vendor/composer/installed.json
vendor/composer/installed.php
vendor/composer/InstalledVersions.php
vendor/composer/LICENSE
vendor/composer/platform_check.php
vendor/psr/container/.gitignore
vendor/psr/container/composer.json
vendor/psr/container/LICENSE
vendor/psr/container/README.md
vendor/psr/container/src/ContainerExceptionInterface.php
vendor/psr/container/src/ContainerInterface.php
vendor/psr/container/src/NotFoundExceptionInterface.php
vendor/psr/log/composer.json
vendor/psr/log/LICENSE
vendor/psr/log/README.md
vendor/psr/log/src/AbstractLogger.php
vendor/psr/log/src/InvalidArgumentException.php
vendor/psr/log/src/LoggerAwareInterface.php
vendor/psr/log/src/LoggerAwareTrait.php
vendor/psr/log/src/LoggerInterface.php
vendor/psr/log/src/LoggerTrait.php
vendor/psr/log/src/LogLevel.php
vendor/psr/log/src/NullLogger.php
vendor/symfony/deprecation-contracts/CHANGELOG.md
vendor/symfony/deprecation-contracts/composer.json
vendor/symfony/deprecation-contracts/function.php
vendor/symfony/deprecation-contracts/LICENSE
vendor/symfony/deprecation-contracts/README.md
vendor/symfony/http-client/AmpHttpClient.php
vendor/symfony/http-client/AsyncDecoratorTrait.php
vendor/symfony/http-client/CachingHttpClient.php
vendor/symfony/http-client/CHANGELOG.md
vendor/symfony/http-client/composer.json
vendor/symfony/http-client/CurlHttpClient.php
vendor/symfony/http-client/DecoratorTrait.php
vendor/symfony/http-client/EventSourceHttpClient.php
vendor/symfony/http-client/HttpClient.php
vendor/symfony/http-client/HttpClientTrait.php
vendor/symfony/http-client/HttplugClient.php
vendor/symfony/http-client/HttpOptions.php
vendor/symfony/http-client/LICENSE
vendor/symfony/http-client/MockHttpClient.php
vendor/symfony/http-client/NativeHttpClient.php
vendor/symfony/http-client/NoPrivateNetworkHttpClient.php
vendor/symfony/http-client/Psr18Client.php
vendor/symfony/http-client/README.md
vendor/symfony/http-client/RetryableHttpClient.php
vendor/symfony/http-client/ScopingHttpClient.php
vendor/symfony/http-client/ThrottlingHttpClient.php
vendor/symfony/http-client/TraceableHttpClient.php
vendor/symfony/http-client/UriTemplateHttpClient.php
vendor/symfony/http-client/Chunk/DataChunk.php
vendor/symfony/http-client/Chunk/ErrorChunk.php
vendor/symfony/http-client/Chunk/FirstChunk.php
vendor/symfony/http-client/Chunk/InformationalChunk.php
vendor/symfony/http-client/Chunk/LastChunk.php
vendor/symfony/http-client/Chunk/ServerSentEvent.php
vendor/symfony/http-client/DataCollector/HttpClientDataCollector.php
vendor/symfony/http-client/DependencyInjection/HttpClientPass.php
vendor/symfony/http-client/Exception/ClientException.php
vendor/symfony/http-client/Exception/EventSourceException.php
vendor/symfony/http-client/Exception/HttpExceptionTrait.php
vendor/symfony/http-client/Exception/InvalidArgumentException.php
vendor/symfony/http-client/Exception/JsonException.php
vendor/symfony/http-client/Exception/RedirectionException.php
vendor/symfony/http-client/Exception/ServerException.php
vendor/symfony/http-client/Exception/TimeoutException.php
vendor/symfony/http-client/Exception/TransportException.php
vendor/symfony/http-client/Internal/AmpBodyV4.php
vendor/symfony/http-client/Internal/AmpBodyV5.php
vendor/symfony/http-client/Internal/AmpClientStateV4.php
vendor/symfony/http-client/Internal/AmpClientStateV5.php
vendor/symfony/http-client/Internal/AmpListenerV4.php
vendor/symfony/http-client/Internal/AmpListenerV5.php
vendor/symfony/http-client/Internal/AmpResolverV4.php
vendor/symfony/http-client/Internal/AmpResolverV5.php
vendor/symfony/http-client/Internal/Canary.php
vendor/symfony/http-client/Internal/ClientState.php
vendor/symfony/http-client/Internal/CurlClientState.php
vendor/symfony/http-client/Internal/DnsCache.php
vendor/symfony/http-client/Internal/HttplugWaitLoop.php
vendor/symfony/http-client/Internal/NativeClientState.php
vendor/symfony/http-client/Internal/PushedResponse.php
vendor/symfony/http-client/Messenger/PingWebhookMessage.php
vendor/symfony/http-client/Messenger/PingWebhookMessageHandler.php
vendor/symfony/http-client/Response/AmpResponseV4.php
vendor/symfony/http-client/Response/AmpResponseV5.php
vendor/symfony/http-client/Response/AsyncContext.php
vendor/symfony/http-client/Response/AsyncResponse.php
vendor/symfony/http-client/Response/CommonResponseTrait.php
vendor/symfony/http-client/Response/CurlResponse.php
vendor/symfony/http-client/Response/HttplugPromise.php
vendor/symfony/http-client/Response/JsonMockResponse.php
vendor/symfony/http-client/Response/MockResponse.php
vendor/symfony/http-client/Response/NativeResponse.php
vendor/symfony/http-client/Response/ResponseStream.php
vendor/symfony/http-client/Response/StreamableInterface.php
vendor/symfony/http-client/Response/StreamWrapper.php
vendor/symfony/http-client/Response/TraceableResponse.php
vendor/symfony/http-client/Response/TransportResponseTrait.php
vendor/symfony/http-client/Retry/GenericRetryStrategy.php
vendor/symfony/http-client/Retry/RetryStrategyInterface.php
vendor/symfony/http-client/Test/HarFileResponseFactory.php
vendor/symfony/http-client-contracts/CHANGELOG.md
vendor/symfony/http-client-contracts/ChunkInterface.php
vendor/symfony/http-client-contracts/composer.json
vendor/symfony/http-client-contracts/HttpClientInterface.php
vendor/symfony/http-client-contracts/LICENSE
vendor/symfony/http-client-contracts/README.md
vendor/symfony/http-client-contracts/ResponseInterface.php
vendor/symfony/http-client-contracts/ResponseStreamInterface.php
vendor/symfony/http-client-contracts/Exception/ClientExceptionInterface.php
vendor/symfony/http-client-contracts/Exception/DecodingExceptionInterface.php
vendor/symfony/http-client-contracts/Exception/ExceptionInterface.php
vendor/symfony/http-client-contracts/Exception/HttpExceptionInterface.php
vendor/symfony/http-client-contracts/Exception/RedirectionExceptionInterface.php
vendor/symfony/http-client-contracts/Exception/ServerExceptionInterface.php
vendor/symfony/http-client-contracts/Exception/TimeoutExceptionInterface.php
vendor/symfony/http-client-contracts/Exception/TransportExceptionInterface.php
vendor/symfony/http-client-contracts/Test/HttpClientTestCase.php
vendor/symfony/http-client-contracts/Test/TestHttpServer.php
vendor/symfony/http-client-contracts/Test/Fixtures/web/index.php
vendor/symfony/service-contracts/CHANGELOG.md
vendor/symfony/service-contracts/composer.json
vendor/symfony/service-contracts/LICENSE
vendor/symfony/service-contracts/README.md
vendor/symfony/service-contracts/ResetInterface.php
vendor/symfony/service-contracts/ServiceCollectionInterface.php
vendor/symfony/service-contracts/ServiceLocatorTrait.php
vendor/symfony/service-contracts/ServiceMethodsSubscriberTrait.php
vendor/symfony/service-contracts/ServiceProviderInterface.php
vendor/symfony/service-contracts/ServiceSubscriberInterface.php
vendor/symfony/service-contracts/ServiceSubscriberTrait.php
vendor/symfony/service-contracts/Attribute/Required.php
vendor/symfony/service-contracts/Attribute/SubscribedService.php
vendor/symfony/service-contracts/Test/ServiceLocatorTest.php
vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2025 magdev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# Listmonk API Client (WiP)
PHP client library for the [Listmonk](https://listmonk.app/) [API](https://listmonk.app/docs/apis/apis/).

21
composer.json Normal file
View File

@@ -0,0 +1,21 @@
{
"name": "magdev/listmonk-api",
"description": "Listmonk API-Client library",
"type": "library",
"license": "MIT",
"minimum-stability": "stable",
"authors": [
{
"name": "magdev",
"email": "magdev3.0@gmail.com"
}
],
"require": {
"symfony/http-client": "^7.3"
},
"autoload": {
"psr-4": {
"Magdev\\ListmonkApi\\": "src/"
}
}
}

445
composer.lock generated Normal file
View File

@@ -0,0 +1,445 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "5699acfabf0a0d069fc5d390bf89915b",
"packages": [
{
"name": "psr/container",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"shasum": ""
},
"require": {
"php": ">=7.4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common Container Interface (PHP FIG PSR-11)",
"homepage": "https://github.com/php-fig/container",
"keywords": [
"PSR-11",
"container",
"container-interface",
"container-interop",
"psr"
],
"support": {
"issues": "https://github.com/php-fig/container/issues",
"source": "https://github.com/php-fig/container/tree/2.0.2"
},
"time": "2021-11-05T16:47:00+00:00"
},
{
"name": "psr/log",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
"shasum": ""
},
"require": {
"php": ">=8.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/3.0.2"
},
"time": "2024-09-11T13:17:53+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
}
},
"autoload": {
"files": [
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.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-25T14:21:43+00:00"
},
{
"name": "symfony/http-client",
"version": "v7.3.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
"reference": "4403d87a2c16f33345dca93407a8714ee8c05a64"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client/zipball/4403d87a2c16f33345dca93407a8714ee8c05a64",
"reference": "4403d87a2c16f33345dca93407a8714ee8c05a64",
"shasum": ""
},
"require": {
"php": ">=8.2",
"psr/log": "^1|^2|^3",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/http-client-contracts": "~3.4.4|^3.5.2",
"symfony/service-contracts": "^2.5|^3"
},
"conflict": {
"amphp/amp": "<2.5",
"amphp/socket": "<1.1",
"php-http/discovery": "<1.15",
"symfony/http-foundation": "<6.4"
},
"provide": {
"php-http/async-client-implementation": "*",
"php-http/client-implementation": "*",
"psr/http-client-implementation": "1.0",
"symfony/http-client-implementation": "3.0"
},
"require-dev": {
"amphp/http-client": "^4.2.1|^5.0",
"amphp/http-tunnel": "^1.0|^2.0",
"guzzlehttp/promises": "^1.4|^2.0",
"nyholm/psr7": "^1.0",
"php-http/httplug": "^1.0|^2.0",
"psr/http-client": "^1.0",
"symfony/amphp-http-client-meta": "^1.0|^2.0",
"symfony/dependency-injection": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/messenger": "^6.4|^7.0",
"symfony/process": "^6.4|^7.0",
"symfony/rate-limiter": "^6.4|^7.0",
"symfony/stopwatch": "^6.4|^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\HttpClient\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
"homepage": "https://symfony.com",
"keywords": [
"http"
],
"support": {
"source": "https://github.com/symfony/http-client/tree/v7.3.1"
},
"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": "2025-06-28T07:58:39+00:00"
},
{
"name": "symfony/http-client-contracts",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client-contracts.git",
"reference": "75d7043853a42837e68111812f4d964b01e5101c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c",
"reference": "75d7043853a42837e68111812f4d964b01e5101c",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\HttpClient\\": ""
},
"exclude-from-classmap": [
"/Test/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to HTTP clients",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/http-client-contracts/tree/v3.6.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": "2025-04-29T11:18:49+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
"reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
"shasum": ""
},
"require": {
"php": ">=8.1",
"psr/container": "^1.1|^2.0",
"symfony/deprecation-contracts": "^2.5|^3"
},
"conflict": {
"ext-psr": "<1.1|>=2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.6-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
},
"exclude-from-classmap": [
"/Test/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to writing services",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.6.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": "2025-04-25T09:37:31+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

20
src/Api/AbstractApi.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
namespace Magdev\ListmonkApi\Api;
use Symfony\Contracts\HttpClient\HttpClientInterface;
abstract class AbstractApi
{
public function __construct(
private HttpClientInterface $client
) {}
protected function getPath(): string
{
return sprintf('/api/%s', $this->getNamespace());
}
abstract protected function query(string $query): array;
abstract protected function getNamespace(): string;
}

8
src/Api/ApiInterface.php Normal file
View File

@@ -0,0 +1,8 @@
<?php
namespace Magdev\ListmonkApi\Api;
interface ApiInterface
{
}

18
src/Api/BounceApi.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
namespace Magdev\ListmonkApi\Api;
use Magdev\ListmonkApi\ListmonkClientNotImplementedException;
class BounceApi extends AbstractApi implements ApiInterface
{
protected function query(string $query): array
{
throw new ListmonkClientNotImplementedException('BounceApi is not implemented yet');
}
protected function getNamespace(): string
{
return 'bounces';
}
}

19
src/Api/CampaignApi.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
namespace Magdev\ListmonkApi\Api;
use Magdev\ListmonkApi\ListmonkClientNotImplementedException;
class CampaignApi extends AbstractApi implements ApiInterface
{
protected function query(string $query): array
{
throw new ListmonkClientNotImplementedException('CampaignApi is not implemented yet');
}
protected function getNamespace(): string
{
return 'campaigns';
}
}

19
src/Api/ImportApi.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
namespace Magdev\ListmonkApi\Api;
use Magdev\ListmonkApi\ListmonkClientNotImplementedException;
class ImportApi extends AbstractApi implements ApiInterface
{
protected function query(string $query): array
{
throw new ListmonkClientNotImplementedException('ImportApi is not implemented yet');
}
protected function getNamespace(): string
{
return 'import';
}
}

18
src/Api/ListApi.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
namespace Magdev\ListmonkApi\Api;
use Magdev\ListmonkApi\ListmonkClientNotImplementedException;
class ListApi extends AbstractApi implements ApiInterface
{
protected function query(string $query): array
{
throw new ListmonkClientNotImplementedException('ListApi is not implemented yet');
}
protected function getNamespace(): string
{
return 'lists';
}
}

18
src/Api/MediaApi.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
namespace Magdev\ListmonkApi\Api;
use Magdev\ListmonkApi\ListmonkClientNotImplementedException;
class MediaApi extends AbstractApi implements ApiInterface
{
protected function query(string $query): array
{
throw new ListmonkClientNotImplementedException('MediaApi is not implemented yet');
}
protected function getNamespace(): string
{
return 'media';
}
}

18
src/Api/SubscriberApi.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
namespace Magdev\ListmonkApi\Api;
use Magdev\ListmonkApi\ListmonkClientNotImplementedException;
class SubscriberApi extends AbstractApi implements ApiInterface
{
protected function query(string $query): array
{
throw new ListmonkClientNotImplementedException('SubscriberApi is not implemented yet');
}
protected function getNamespace(): string
{
return 'subscribers';
}
}

18
src/Api/TemplateApi.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
namespace Magdev\ListmonkApi\Api;
use Magdev\ListmonkApi\ListmonkClientNotImplementedException;
class TemplateApi extends AbstractApi implements ApiInterface
{
protected function query(string $query): array
{
throw new ListmonkClientNotImplementedException('TemplateApi is not implemented yet');
}
protected function getNamespace(): string
{
return 'templates';
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Magdev\ListmonkApi\Api;
use Magdev\ListmonkApi\ListmonkClientNotImplementedException;
class TransactionalApi extends AbstractApi implements ApiInterface
{
protected function query(string $query): array
{
throw new ListmonkClientNotImplementedException('TransactionalApi is not implemented yet');
}
protected function getNamespace(): string
{
return 'tx';
}
}

97
src/ListmonkClient.php Normal file
View File

@@ -0,0 +1,97 @@
<?php
namespace Magdev\ListmonkApi;
use Magdev\ListmonkApi\Api\BounceApi;
use Magdev\ListmonkApi\Api\CampaignApi;
use Magdev\ListmonkApi\Api\ImportApi;
use Magdev\ListmonkApi\Api\ListApi;
use Magdev\ListmonkApi\Api\MediaApi;
use Magdev\ListmonkApi\Api\SubscriberApi;
use Magdev\ListmonkApi\Api\TemplateApi;
use Magdev\ListmonkApi\Api\TransactionalApi;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Contracts\HttpClient\HttpClientInterface;
class ListmonkClient
{
protected ?HttpClientInterface $client = null;
public function __construct(?HttpClientInterface $client = null)
{
if ($client instanceof HttpClientInterface) {
$this->setClient($client);
}
}
public function connect(string $hostname, string $username, string $token): static
{
if ($this->client instanceof HttpClientInterface) {
return $this;
}
$this->client = HttpClient::createForBaseUri($hostname, [
'headers' => [
'Authorization' => sprintf('token %s:%s', $username, $token),
]
]);
return $this;
}
public function getClient(): ?HttpClientInterface
{
if (is_null($this->client)) {
throw new ListmonkClientException('You have to connect to a server first or set the client manually');
}
return $this->client;
}
public function setClient(HttpClientInterface $client): static
{
$this->client = $client;
return $this;
}
public function subscribers(): SubscriberApi
{
return new SubscriberApi($this->getClient());
}
public function transactional(): TransactionalApi
{
return new TransactionalApi($this->getClient());
}
public function lists(): ListApi
{
return new ListApi($this->getClient());
}
public function bounces(): BounceApi
{
return new BounceApi($this->getClient());
}
public function templates(): TemplateApi
{
return new TemplateApi($this->getClient());
}
public function media(): MediaApi
{
return new MediaApi($this->getClient());
}
public function campaigns(): CampaignApi
{
return new CampaignApi($this->getClient());
}
public function import(): ImportApi
{
return new ImportApi($this->getClient());
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Magdev\ListmonkApi;
class ListmonkClientException extends \RuntimeException
{
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Magdev\ListmonkApi;
class ListmonkClientNotImplementedException extends \BadMethodCallException
{
}

View File

@@ -0,0 +1,17 @@
<?php
namespace Magdev\ListmonkApi\Model;
use Magdev\ListmonkApi\Model\Traits\DefaultPropertiesTrait;
abstract class AbstractModel
{
use DefaultPropertiesTrait;
public function __construct(?array $data = null)
{
if (is_array($data)) {
$this->fromArray($data);
}
}
}

359
src/Model/CampaignModel.php Normal file
View File

@@ -0,0 +1,359 @@
<?php
namespace Magdev\ListmonkApi\Model;
class CampaignModel extends AbstractModel implements ModelInterface
{
protected ?int $views = null;
protected ?int $clicks = null;
protected ?array $lists = null;
protected ?\DateTimeInterface $startedAt = null;
protected ?\DateTimeInterface $sendAt = null;
protected ?int $toSend = null;
protected ?int $sent = null;
protected ?string $type = null;
protected ?string $name = null;
protected ?string $subject = null;
protected ?string $fromEmail = null;
protected ?string $body = null;
protected ?string $bodySource = null;
protected ?string $status = null;
protected ?string $contentType = null;
protected ?array $tags = null;
protected ?string $messenger = null;
protected ?int $templateId = null;
public function fromArray(array $data): static
{
parent::fromArray($data);
if (isset($data['name'])) {
$this->setName($data['name']);
}
if (isset($data['type'])) {
$this->setType($data['type']);
}
if (isset($data['from_email'])) {
$this->setFromEmail($data['from_email']);
}
if (isset($data['views'])) {
$this->setViews($data['views']);
}
if (isset($data['clicks'])) {
$this->setClicks($data['clicks']);
}
if (isset($data['to_send'])) {
$this->setToSend($data['to_send']);
}
if (isset($data['sent'])) {
$this->setSent($data['sent']);
}
if (isset($data['send_at'])) {
$this->setSendAt($data['send_at']);
}
if (isset($data['started_at'])) {
$this->setStartedAt($data['started_at']);
}
if (isset($data['subject'])) {
$this->setSubject($data['subject']);
}
if (isset($data['body'])) {
$this->setBody($data['body']);
}
if (isset($data['body_source'])) {
$this->setBodySource($data['body_source']);
}
if (isset($data['status'])) {
$this->setStatus($data['status']);
}
if (isset($data['content_type'])) {
$this->setContentType($data['content_type']);
}
if (isset($data['tags'])) {
$this->setTags($data['tags']);
}
if (isset($data['messenger'])) {
$this->setMessenger($data['messenger']);
}
if (isset($data['template_id'])) {
$this->setTemplateId($data['template_id']);
}
if (isset($data['lists']) && is_array($data['lists'])) {
foreach ($data['lists'] as $listData) {
$this->addList(new ListModel($listData));
}
}
return $this;
}
public function toArray(): array
{
$data = array_merge(parent::toArray(), [
'name' => $this->getName(),
'type' => $this->getType(),
'from_email' => $this->getFromEmail(),
'views' => $this->getViews(),
'clicks' => $this->getClicks(),
'to_send' => $this->getToSend(),
'sent' => $this->getSent(),
'send_at' => $this->getSendAt(),
'started_at' => $this->getStartedAt(),
'subject' => $this->getSubject(),
'body' => $this->getBody(),
'body_source' => $this->getBodySource(),
'status' => $this->getStatus(),
'content_type' => $this->getContentType(),
'tags' => $this->getTags(),
'messenger' => $this->getMessenger(),
'template_id' => $this->getTemplateId(),
'lists' => [],
]);
if ($lists = $this->getLists()) {
foreach ($lists as $list) {
$data['lists'][] = $list->toArray();
}
}
return $data;
}
public function getViews(): ?int
{
return $this->views;
}
public function setViews(?int $views): self
{
$this->views = $views;
return $this;
}
public function getClicks(): ?int
{
return $this->clicks;
}
public function setClicks(?int $clicks): self
{
$this->clicks = $clicks;
return $this;
}
/**
* @return ListModel[]|null
*/
public function getLists(): ?array
{
return $this->lists;
}
/**
* @param ListModel[]|null
*/
public function setLists(?array $lists): self
{
$this->lists = $lists;
return $this;
}
public function addList(ListModel $list): self
{
$this->lists[] = $list;
return $this;
}
public function getStartedAt(): ?\DateTimeInterface
{
return $this->startedAt;
}
public function setStartedAt(\DateTimeInterface|string|null $startedAt): self
{
if (is_string($startedAt)) {
$startedAt = new \DateTime($startedAt);
}
$this->startedAt = $startedAt;
return $this;
}
public function getSendAt(): ?\DateTimeInterface
{
return $this->sendAt;
}
public function setSendAt(\DateTimeInterface|string|null $sendAt): self
{
if (is_string($sendAt)) {
$sendAt = new \DateTime($sendAt);
}
$this->sendAt = $sendAt;
return $this;
}
public function getToSend(): ?int
{
return $this->toSend;
}
public function setToSend(?int $toSend): self
{
$this->toSend = $toSend;
return $this;
}
public function getSent(): ?int
{
return $this->sent;
}
public function setSent(?int $sent): self
{
$this->sent = $sent;
return $this;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(?string $type): self
{
$this->type = $type;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): self
{
$this->name = $name;
return $this;
}
public function getSubject(): ?string
{
return $this->subject;
}
public function setSubject(?string $subject): self
{
$this->subject = $subject;
return $this;
}
public function getFromEmail(): ?string
{
return $this->fromEmail;
}
public function setFromEmail(?string $fromEmail): self
{
$this->fromEmail = $fromEmail;
return $this;
}
public function getBody(): ?string
{
return $this->body;
}
public function setBody(?string $body): self
{
$this->body = $body;
return $this;
}
public function getBodySource(): ?string
{
return $this->bodySource;
}
public function setBodySource(?string $bodySource): self
{
$this->bodySource = $bodySource;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(?string $status): self
{
$this->status = $status;
return $this;
}
public function getContentType(): ?string
{
return $this->contentType;
}
public function setContentType(?string $contentType): self
{
$this->contentType = $contentType;
return $this;
}
public function getTags(): ?array
{
return $this->tags;
}
public function setTags(?array $tags): self
{
$this->tags = $tags;
return $this;
}
public function getMessenger(): ?string
{
return $this->messenger;
}
public function setMessenger(?string $messenger): self
{
$this->messenger = $messenger;
return $this;
}
public function getTemplateId(): ?int
{
return $this->templateId;
}
public function setTemplateId(?int $templateId): self
{
$this->templateId = $templateId;
return $this;
}
}

123
src/Model/ListModel.php Normal file
View File

@@ -0,0 +1,123 @@
<?php
namespace Magdev\ListmonkApi\Model;
class ListModel extends AbstractModel implements ModelInterface
{
protected ?string $name = null;
protected ?string $type = null;
protected ?array $tags = null;
protected ?string $optin = null;
protected ?string $subscriptionStatus = null;
protected ?int $subscriberCount = null;
public function fromArray(array $data): static
{
parent::fromArray($data);
if (isset($data['name'])) {
$this->setName($data['name']);
}
if (isset($data['type'])) {
$this->setType($data['type']);
}
if (isset($data['tags'])) {
$this->setTags($data['tags']);
}
if (isset($data['optin'])) {
$this->setOptin($data['optin']);
}
if (isset($data['subscription_status'])) {
$this->setSubscriptionStatus($data['subscription_status']);
}
if (isset($data['subscriber_count'])) {
$this->setSubscriberCount($data['subscriber_count']);
}
return $this;
}
public function toArray(): array
{
return array_merge(parent::toArray(), [
'name' => $this->getName(),
'type' => $this->getType(),
'tags' => $this->getTags(),
'optin' => $this->getOptin(),
'subscription_status' => $this->getSubscriptionStatus(),
'subscriber_count' => $this->getSubscriberCount(),
]);
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): self
{
$this->name = $name;
return $this;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(?string $type): self
{
$this->type = $type;
return $this;
}
public function getTags(): ?array
{
return $this->tags;
}
public function setTags(?array $tags): self
{
$this->tags = $tags;
return $this;
}
public function getOptin(): ?string
{
return $this->optin;
}
public function setOptin(?string $optin): self
{
$this->optin = $optin;
return $this;
}
public function getSubscriptionStatus(): ?string
{
return $this->subscriptionStatus;
}
public function setSubscriptionStatus(?string $subscriptionStatus): self
{
$this->subscriptionStatus = $subscriptionStatus;
return $this;
}
public function getSubscriberCount(): ?int
{
return $this->subscriberCount;
}
public function setSubscriberCount(?int $subscriberCount): self
{
$this->subscriberCount = $subscriberCount;
return $this;
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace Magdev\ListmonkApi\Model;
interface ModelInterface
{
public function toArray(): array;
public function fromArray(array $data): static;
}

View File

@@ -0,0 +1,128 @@
<?php
namespace Magdev\ListmonkApi\Model;
class SubscriberModel extends AbstractModel implements ModelInterface
{
protected ?string $email = null;
protected ?string $name = null;
protected ?array $attribs = null;
protected ?string $status = null;
protected ?array $lists = null;
public function fromArray(array $data): static
{
parent::fromArray($data);
if (isset($data['email'])) {
$this->setEmail($data['email']);
}
if (isset($data['name'])) {
$this->setName($data['name']);
}
if (isset($data['attribs'])) {
$this->setAttribs($data['attribs']);
}
if (isset($data['status'])) {
$this->setStatus($data['status']);
}
if (isset($data['lists']) && is_array($data['lists'])) {
foreach ($data['lists'] as $listData) {
$this->addList(new ListModel($listData));
}
}
return $this;
}
public function toArray(): array
{
$data = array_merge(parent::toArray(), [
'email' => $this->getEmail(),
'name' => $this->getName(),
'attribs' => $this->getAttribs(),
'status' => $this->getStatus(),
'lists' => [],
]);
foreach ($this->getLists() as $list) {
$data['lists'][] = $list->toArray();
}
return $data;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(?string $email): self
{
$this->email = $email;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): self
{
$this->name = $name;
return $this;
}
public function getAttribs(): ?array
{
return $this->attribs;
}
public function setAttribs(?array $attribs): self
{
$this->attribs = $attribs;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(?string $status): self
{
$this->status = $status;
return $this;
}
/**
* @return ListModel[]|null
*/
public function getLists(): ?array
{
return $this->lists;
}
/**
* @param ListModel[]|null
*/
public function setLists(?array $lists): self
{
$this->lists = $lists;
return $this;
}
public function addList(ListModel $list): self
{
$this->lists[] = $list;
return $this;
}
}

View File

@@ -0,0 +1,95 @@
<?php
namespace Magdev\ListmonkApi\Model\Traits;
trait DefaultPropertiesTrait
{
protected ?int $id = null;
protected ?string $uuid = null;
protected ?\DateTimeInterface $createdAt = null;
protected ?\DateTimeInterface $updatedAt = null;
public function getId(): ?int
{
return $this->id;
}
public function setId(?int $id): self
{
$this->id = $id;
return $this;
}
public function getUuid(): ?string
{
return $this->uuid;
}
public function setUuid(?string $uuid): self
{
$this->uuid = $uuid;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface|string|null $createdAt): self
{
if (is_string($createdAt)) {
$createdAt = new \DateTime($createdAt);
}
$this->createdAt = $createdAt;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(\DateTimeInterface|string|null $updatedAt): self
{
if (is_string($updatedAt)) {
$updatedAt = new \DateTime($updatedAt);
}
$this->updatedAt = $updatedAt;
return $this;
}
public function fromArray(array $data): static
{
if (isset($data['id'])) {
$this->setId($data['id']);
}
if (isset($data['uuid'])) {
$this->setUuid($data['uuid']);
}
if (isset($data['created_at'])) {
$this->setCreatedAt($data['created_at']);
}
if (isset($data['updated_at'])) {
$this->setUpdatedAt($data['updated_at']);
}
return $this;
}
public function toArray(): array
{
return [
'id' => $this->getId(),
'uuid' => $this->getUuid(),
'created_at' => $this->getCreatedAt(),
'updated_at' => $this->getUpdatedAt(),
];
}
}