Completed
Pull Request — master (#202)
by David
01:22
created

Newsletter::retry()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 2
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
namespace Spatie\Newsletter;
4
5
use Exception;
6
use DrewM\MailChimp\MailChimp;
7
8
class Newsletter
9
{
10
    /** @var \DrewM\MailChimp\MailChimp */
11
    protected $mailChimp;
12
13
    /** @var \Spatie\Newsletter\NewsletterListCollection */
14
    protected $lists;
15
16
    public function __construct(MailChimp $mailChimp, NewsletterListCollection $lists)
17
    {
18
        $this->mailChimp = $mailChimp;
19
20
        $this->lists = $lists;
21
    }
22
23 View Code Duplication
    public function subscribe(string $email, array $mergeFields = [], string $listName = '', array $options = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
24
    {
25
        $list = $this->lists->findByName($listName);
26
27
        $options = $this->getSubscriptionOptions($email, $mergeFields, $options);
28
29
        $response = $this->mailChimp->post("lists/{$list->getId()}/members", $options);
30
31
        if (! $this->lastActionSucceeded()) {
32
            return false;
33
        }
34
35
        return $response;
36
    }
37
38
    public function subscribePending(string $email, array $mergeFields = [], string $listName = '', array $options = [])
39
    {
40
        $options = array_merge($options, ['status' => 'pending']);
41
42
        return $this->subscribe($email, $mergeFields, $listName, $options);
43
    }
44
45 View Code Duplication
    public function subscribeOrUpdate(string $email, array $mergeFields = [], string $listName = '', array $options = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
46
    {
47
        $list = $this->lists->findByName($listName);
48
49
        $options = $this->getSubscriptionOptions($email, $mergeFields, $options);
50
51
        $response = $this->mailChimp->put("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}", $options);
52
53
        if (! $this->lastActionSucceeded()) {
54
            return false;
55
        }
56
57
        return $response;
58
    }
59
60
    public function getMembers(string $listName = '', array $parameters = [])
61
    {
62
        $list = $this->lists->findByName($listName);
63
64
        return $this->mailChimp->get("lists/{$list->getId()}/members", $parameters);
65
    }
66
67
    /**
68
     * 
69
     *  Get all the members from a list, trying to recover from failure (useful for large lists)
70
     * 
71
     * @return array
72
     * @throws \Exception thrown by Mailchimp API
73
     * @throws \DomainException if we can't get a valid result
74
     * */
75
    public function getAllMembers(string $listName = '', array $parameters = []): array
76
    {
77
        $total = $this->getMembers($listName, $parameters)['total_items'];
78
79
        $members = [];
80
81
        for ($i = 0; $i < $total; $i += 500) {
82
83
            $payload = array_merge($parameters, ['count'  => 500, 'offset' => $i]);
84
85
            $members = array_merge(
86
                $members,
87
                $this->retry(function () use ($payload, $listName) {
88
89
                    $members = $this->getMembers($listName, $payload);
90
91
                    if ( ! is_array($members) || ! isset($members['members'])) {
92
                        throw new \DomainException($this->getLastError());
93
                    }
94
95
                    return $members['members'];
96
                })
97
            );
98
99
        }
100
101
        return $members;
102
    }
103
104
    public function getMember(string $email, string $listName = '')
105
    {
106
        $list = $this->lists->findByName($listName);
107
108
        return $this->mailChimp->get("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}");
109
    }
110
111
    public function getMemberActivity(string $email, string $listName = '')
112
    {
113
        $list = $this->lists->findByName($listName);
114
115
        return $this->mailChimp->get("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}/activity");
116
    }
117
118
    public function hasMember(string $email, string $listName = ''): bool
119
    {
120
        $response = $this->getMember($email, $listName);
121
122
        if (! isset($response['email_address'])) {
123
            return false;
124
        }
125
126
        if (strtolower($response['email_address']) != strtolower($email)) {
127
            return false;
128
        }
129
130
        return true;
131
    }
132
133
    public function isSubscribed(string $email, string $listName = ''): bool
134
    {
135
        $response = $this->getMember($email, $listName);
136
137
        if (! isset($response)) {
138
            return false;
139
        }
140
141
        if ($response['status'] != 'subscribed') {
142
            return false;
143
        }
144
145
        return true;
146
    }
147
148 View Code Duplication
    public function unsubscribe(string $email, string $listName = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
149
    {
150
        $list = $this->lists->findByName($listName);
151
152
        $response = $this->mailChimp->patch("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}", [
153
            'status' => 'unsubscribed',
154
        ]);
155
156
        if (! $this->lastActionSucceeded()) {
157
            return false;
158
        }
159
160
        return $response;
161
    }
162
163 View Code Duplication
    public function updateEmailAddress(string $currentEmailAddress, string $newEmailAddress, string $listName = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
164
    {
165
        $list = $this->lists->findByName($listName);
166
167
        $response = $this->mailChimp->patch("lists/{$list->getId()}/members/{$this->getSubscriberHash($currentEmailAddress)}", [
168
            'email_address' => $newEmailAddress,
169
        ]);
170
171
        return $response;
172
    }
173
174
    public function delete(string $email, string $listName = '')
175
    {
176
        $list = $this->lists->findByName($listName);
177
178
        $response = $this->mailChimp->delete("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}");
179
180
        return $response;
181
    }
182
183
    public function getTags(string $email, string $listName = '')
184
    {
185
        $list = $this->lists->findByName($listName);
186
187
        return $this->mailChimp->get("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}/tags");
188
    }
189
190 View Code Duplication
    public function addTags(array $tags, string $email, string $listName = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
191
    {
192
        $list = $this->lists->findByName($listName);
193
194
        $payload = collect($tags)->mapWithKeys(function ($tag) {
195
            return [$tag => 'active'];
196
        })->toArray();
197
198
        return $this->mailChimp->post("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}/tags", [
199
            'tags' => $payload,
200
        ]);
201
    }
202
203 View Code Duplication
    public function removeTags(array $tags, string $email, string $listName = '')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
204
    {
205
        $list = $this->lists->findByName($listName);
206
207
        $payload = collect($tags)->mapWithKeys(function ($tag) {
208
            return [$tag => 'inactive'];
209
        })->toArray();
210
211
        return $this->mailChimp->post("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}/tags", [
212
            'tags' => $payload,
213
        ]);
214
    }
215
216
    public function createCampaign(
217
        string $fromName,
218
        string $replyTo,
219
        string $subject,
220
        string $html = '',
221
        string $listName = '',
222
        array $options = [],
223
        array $contentOptions = [])
224
    {
225
        $list = $this->lists->findByName($listName);
226
227
        $defaultOptions = [
228
            'type' => 'regular',
229
            'recipients' => [
230
                'list_id' => $list->getId(),
231
            ],
232
            'settings' => [
233
                'subject_line' => $subject,
234
                'from_name' => $fromName,
235
                'reply_to' => $replyTo,
236
            ],
237
        ];
238
239
        $options = array_merge($defaultOptions, $options);
240
241
        $response = $this->mailChimp->post('campaigns', $options);
242
243
        if (! $this->lastActionSucceeded()) {
244
            return false;
245
        }
246
247
        if ($html === '') {
248
            return $response;
249
        }
250
251
        if (! $this->updateContent($response['id'], $html, $contentOptions)) {
252
            return false;
253
        }
254
255
        return $response;
256
    }
257
258
    public function updateContent(string $campaignId, string $html, array $options = [])
259
    {
260
        $defaultOptions = compact('html');
261
262
        $options = array_merge($defaultOptions, $options);
263
264
        $response = $this->mailChimp->put("campaigns/{$campaignId}/content", $options);
265
266
        if (! $this->lastActionSucceeded()) {
267
            return false;
268
        }
269
270
        return $response;
271
    }
272
273
    public function getApi(): MailChimp
274
    {
275
        return $this->mailChimp;
276
    }
277
278
    /**
279
     * @return array|false
280
     */
281
    public function getLastError()
282
    {
283
        return $this->mailChimp->getLastError();
284
    }
285
286
    public function lastActionSucceeded(): bool
287
    {
288
        return $this->mailChimp->success();
289
    }
290
291
    protected function getSubscriberHash(string $email): string
292
    {
293
        return $this->mailChimp->subscriberHash($email);
294
    }
295
296
    protected function getSubscriptionOptions(string $email, array $mergeFields, array $options): array
297
    {
298
        $defaultOptions = [
299
            'email_address' => $email,
300
            'status' => 'subscribed',
301
            'email_type' => 'html',
302
        ];
303
304
        if (count($mergeFields)) {
305
            $defaultOptions['merge_fields'] = $mergeFields;
306
        }
307
308
        $options = array_merge($defaultOptions, $options);
309
310
        return $options;
311
    }
312
313
    private function retry($callback, int $max = 10)
314
    {
315
        while ($max-- > 0) {
316
            try {
317
318
                return $callback();
319
320
            } catch (Exception $e) {
321
                sleep(10);
322
            }
323
        }
324
325
        throw($e);
326
    }
327
}
328