Skip to content

Commit 3258e4b

Browse files
authored
Add Campaign Filtering, Template Management, and Bounce API Improvements
Summary This PR expands campaign, template, and bounce-related API functionality. It adds new query parameters, template routing support, ordering options, and additional bounce endpoints/methods for campaign and subscriber-specific bounce handling. Changes Campaigns Added support for queryParams.subject in getCampaigns Allows filtering or searching campaigns by subject Templates Added template update method Added default template routes Added order support to template request handling CodeRabbit Added CodeRabbit integration/configuration Bounces Added list bounces endpoint Added status parameter support for bounces Added methods for retrieving bounces by campaign Added methods for retrieving bounces by subscriber Updated bounce rules handling to use id as a parameter
2 parents fd580a3 + 4c82f65 commit 3258e4b

11 files changed

Lines changed: 1092 additions & 177 deletions

File tree

.github/workflows/ci.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@ jobs:
4646
- name: Install Prism
4747
run: npm install -g @stoplight/prism-cli
4848

49-
- name: List files
50-
run: ls -al
51-
5249
- name: Start Prism Mock Server
5350
run: prism mock ./openapi.json &
5451

openapi.json

Lines changed: 796 additions & 152 deletions
Large diffs are not rendered by default.

src/Endpoint/BouncesClient.php

Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use PhpList\RestApiClient\Client;
88
use PhpList\RestApiClient\Exception\ApiException;
9+
use PhpList\RestApiClient\Response\Bounces\BounceCollection;
910

1011
/**
1112
* Client for bounce-related API endpoints.
@@ -32,6 +33,64 @@ public function listRegex(): array
3233
return $this->client->get('bounces/regex');
3334
}
3435

36+
/**
37+
* Get a list of all bounces.
38+
*
39+
* GET /api/v2/bounces
40+
*
41+
* @return BounceCollection
42+
* @throws ApiException If an API error occurs
43+
*/
44+
public function list(?int $afterId = null, ?int $limit = 25, ?string $status = null): BounceCollection
45+
{
46+
$queryParams = ['limit' => $limit];
47+
48+
if ($afterId !== null) {
49+
$queryParams['after_id'] = $afterId;
50+
}
51+
if ($status !== null) {
52+
$queryParams['status'] = $status;
53+
}
54+
$response = $this->client->get('bounces', ['query' => $queryParams]);
55+
return new BounceCollection($response);
56+
}
57+
58+
/**
59+
* Get a list of bounce counts by campaign.
60+
*
61+
* GET /api/v2/bounces/by/campaign
62+
*
63+
* @return array<int, array{
64+
* message_id: int,
65+
* subject: string,
66+
* total_bounces: int
67+
* }> Raw API response
68+
* @throws ApiException If an API error occurs
69+
*/
70+
public function listByCampaign(): array
71+
{
72+
return $this->client->get('bounces/by/campaign');
73+
}
74+
75+
/**
76+
* Get a list of bounce counts by subscriber.
77+
*
78+
* GET /api/v2/bounces/by/subscriber
79+
*
80+
* @return array<int, array{
81+
* subscriber_id: int,
82+
* email: string,
83+
* confirmed: bool,
84+
* blacklisted: bool,
85+
* total_bounces: int
86+
* }> Raw API response
87+
* @throws ApiException If an API error occurs
88+
*/
89+
public function listBySubscriber(): array
90+
{
91+
return $this->client->get('bounces/by/subscriber');
92+
}
93+
3594
/**
3695
* Create or update a bounce regex rule.
3796
*
@@ -47,30 +106,44 @@ public function upsertRegex(array $data): array
47106
}
48107

49108
/**
50-
* Get a bounce regex rule by its hash.
109+
* Get a bounce regex rule by its id.
51110
*
52-
* GET /api/v2/bounces/regex/{regexHash}
111+
* GET /api/v2/bounces/regex/{ruleId}
53112
*
54-
* @param string $regexHash The regex hash
113+
* @param int $ruleId The regex id
55114
* @return array The regex data
56115
* @throws ApiException If an API error occurs
57116
*/
58-
public function getRegexByHash(string $regexHash): array
117+
public function getOne(int $ruleId): array
118+
{
119+
return $this->client->get('bounces/regex/' . $ruleId);
120+
}
121+
122+
/**
123+
* Delete a bounce regex rule by its id.
124+
*
125+
* DELETE /api/v2/bounces/regex/{ruleId}
126+
*
127+
* @param int $ruleId The regex id
128+
* @return array Empty response on success
129+
* @throws ApiException If an API error occurs
130+
*/
131+
public function delete(int $ruleId): array
59132
{
60-
return $this->client->get('bounces/regex/' . rawurlencode($regexHash));
133+
return $this->client->delete('bounces/regex/' . $ruleId);
61134
}
62135

63136
/**
64-
* Delete a bounce regex rule by its hash.
137+
* Delete a bounce by its id.
65138
*
66-
* DELETE /api/v2/bounces/regex/{regexHash}
139+
* DELETE /api/v2/bounces/{bounceId}
67140
*
68-
* @param string $regexHash The regex hash
141+
* @param string $bounceId The bounce id
69142
* @return array Empty response on success
70143
* @throws ApiException If an API error occurs
71144
*/
72-
public function deleteRegexByHash(string $regexHash): array
145+
public function deleteById(string $bounceId): array
73146
{
74-
return $this->client->delete('bounces/regex/' . rawurlencode($regexHash));
147+
return $this->client->delete('bounces/' . rawurlencode($bounceId));
75148
}
76149
}

src/Endpoint/CampaignClient.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,28 @@ public function __construct(Client $client)
3333
$this->client = $client;
3434
}
3535

36+
3637
/**
3738
* Get a list of campaigns.
3839
*
3940
* @param int|null $afterId The ID to start from for pagination
4041
* @param int $limit The maximum number of items to return
42+
* @param string|null $subject Filter campaigns by subject
4143
* @return CampaignCollection The list of campaigns
4244
* @throws ApiException If an API error occurs
4345
*/
44-
public function getCampaigns(?int $afterId = null, int $limit = 25): CampaignCollection
46+
public function getCampaigns(?int $afterId = null, int $limit = 25, ?string $subject = null): CampaignCollection
4547
{
4648
$queryParams = ['limit' => $limit];
4749

4850
if ($afterId !== null) {
4951
$queryParams['after_id'] = $afterId;
5052
}
5153

54+
if ($subject !== null) {
55+
$queryParams['subject'] = $subject;
56+
}
57+
5258
$response = $this->client->get('campaigns', $queryParams);
5359
return new CampaignCollection($response);
5460
}

src/Endpoint/TemplatesClient.php

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use PhpList\RestApiClient\Exception\ApiException;
1010
use PhpList\RestApiClient\Exception\NotFoundException;
1111
use PhpList\RestApiClient\Exception\ValidationException;
12-
use PhpList\RestApiClient\Request\Template\CreateTemplateRequest;
12+
use PhpList\RestApiClient\Request\Template\TemplateRequest;
1313
use PhpList\RestApiClient\Response\TemplateCollection;
1414

1515
/**
@@ -69,17 +69,32 @@ public function getTemplate(string $id): Template
6969
/**
7070
* Create a new template.
7171
*
72-
* @param CreateTemplateRequest $request The template request
72+
* @param TemplateRequest $request The template request
7373
* @return Template The created template
7474
* @throws ValidationException If validation fails
7575
* @throws ApiException If an API error occurs
7676
*/
77-
public function createTemplate(CreateTemplateRequest $request): Template
77+
public function createTemplate(TemplateRequest $request): Template
7878
{
7979
$response = $this->client->post('templates', $request->toArray());
8080
return new Template($response);
8181
}
8282

83+
/**
84+
* Update template.
85+
*
86+
* @param TemplateRequest $request The template request
87+
* @param int $templateId The template ID
88+
* @return Template The updated template
89+
* @throws ValidationException If validation fails
90+
* @throws ApiException If an API error occurs
91+
*/
92+
public function updateTemplate(TemplateRequest $request, int $templateId): Template
93+
{
94+
$response = $this->client->put('templates/' . $templateId, $request->toArray());
95+
return new Template($response);
96+
}
97+
8398
/**
8499
* Delete a template.
85100
*
@@ -91,4 +106,14 @@ public function deleteTemplate(string $id): void
91106
{
92107
$this->client->delete('templates/' . $id);
93108
}
109+
110+
public function getDefaultTemplates(): void
111+
{
112+
$this->client->get('templates/defaults');
113+
}
114+
115+
public function createFromDefault(string $key): void
116+
{
117+
$this->client->post('templates/defaults/' . $key);
118+
}
94119
}

src/Entity/Bounce.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\RestApiClient\Entity;
6+
7+
use PhpList\RestApiClient\Response\AbstractResponse;
8+
9+
/**
10+
* Entity representing a bounce record.
11+
*/
12+
class Bounce extends AbstractResponse
13+
{
14+
public int $id;
15+
public ?string $status = null;
16+
public ?string $date = null;
17+
public int $messageId;
18+
public ?string $messageSubject = null;
19+
public ?int $subscriberId = null;
20+
public ?string $subscriberEmail = null;
21+
public ?string $comment = null;
22+
23+
public function __construct(array $data)
24+
{
25+
$this->id = isset($data['id']) ? (int)$data['id'] : 0;
26+
$this->status = isset($data['status']) ? (string)$data['status'] : null;
27+
$this->date = isset($data['date']) ? (string)$data['date'] : null;
28+
$this->messageId = isset($data['message_id']) ? (int)$data['message_id'] : 0;
29+
$this->messageSubject = isset($data['message_subject']) ? (string)$data['message_subject'] : null;
30+
$this->subscriberId = isset($data['subscriber_id']) ? (int)$data['subscriber_id'] : null;
31+
$this->subscriberEmail = isset($data['subscriber_email']) ? (string)$data['subscriber_email'] : null;
32+
$this->comment = isset($data['comment']) ? (string)$data['comment'] : null;
33+
}
34+
}

src/Entity/Template.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class Template extends AbstractResponse
3434
/**
3535
* @var string|null
3636
*/
37-
public ?string $order = null;
37+
public ?string $listOrder = null;
3838

3939
/**
4040
* @var ?array
@@ -47,7 +47,7 @@ public function __construct(array $data)
4747
$this->title = isset($data['title']) ? (string)$data['title'] : '';
4848
$this->text = isset($data['text']) ? (string)$data['text'] : null;
4949
$this->content = isset($data['content']) ? (string)$data['content'] : null;
50-
$this->order = isset($data['order']) ? (string)$data['order'] : null;
50+
$this->listOrder = isset($data['list_order']) ? (string)$data['list_order'] : null;
5151

5252
$this->images = isset($data['images']) && is_array($data['images']) ? $data['images'] : null;
5353
}

src/Request/Template/CreateTemplateRequest.php renamed to src/Request/Template/TemplateRequest.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
/**
1010
* Request class for creating a new template.
1111
*/
12-
class CreateTemplateRequest extends AbstractRequest
12+
class TemplateRequest extends AbstractRequest
1313
{
1414
/**
1515
* @var string The title of the template
@@ -45,6 +45,7 @@ class CreateTemplateRequest extends AbstractRequest
4545
* @var bool|null Check that all external images exist
4646
*/
4747
public ?bool $checkExternalImages = null;
48+
public ?int $listOrder = null;
4849

4950
/**
5051
* CreateTemplateRequest constructor.
@@ -56,6 +57,7 @@ class CreateTemplateRequest extends AbstractRequest
5657
* @param bool|null $checkLinks Check that all links have full URLs
5758
* @param bool|null $checkImages Check that all images have full URLs
5859
* @param bool|null $checkExternalImages Check that all external images exist
60+
* @param int|null $listOrder The order in which the template should appear in lists
5961
*/
6062
public function __construct(
6163
string $title,
@@ -64,7 +66,8 @@ public function __construct(
6466
?string $file = null,
6567
?bool $checkLinks = null,
6668
?bool $checkImages = null,
67-
?bool $checkExternalImages = null
69+
?bool $checkExternalImages = null,
70+
?int $listOrder = null,
6871
) {
6972
$this->title = $title;
7073
$this->content = $content;
@@ -73,5 +76,6 @@ public function __construct(
7376
$this->checkLinks = $checkLinks;
7477
$this->checkImages = $checkImages;
7578
$this->checkExternalImages = $checkExternalImages;
79+
$this->listOrder = $listOrder;
7680
}
7781
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\RestApiClient\Response\Bounces;
6+
7+
use PhpList\RestApiClient\Entity\Bounce;
8+
use PhpList\RestApiClient\Response\AbstractCollectionResponse;
9+
10+
/**
11+
* Response class for a list of bounces.
12+
*/
13+
class BounceCollection extends AbstractCollectionResponse
14+
{
15+
/**
16+
* @var Bounce[] The list of bounces
17+
*/
18+
public array $items = [];
19+
20+
public function __construct(array $data)
21+
{
22+
if (!isset($data['items']) || !is_array($data['items'])) {
23+
$data = [
24+
'items' => $data,
25+
'pagination' => [
26+
'total' => count($data),
27+
'limit' => count($data),
28+
'has_more' => false,
29+
'next_cursor' => null,
30+
],
31+
];
32+
}
33+
34+
parent::__construct($data);
35+
}
36+
37+
protected function processItems(array $items): void
38+
{
39+
$this->items = [];
40+
foreach ($items as $item) {
41+
$this->items[] = new Bounce($item);
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)