Completed
Pull Request — master (#202)
by David
02:26 queued 01:03
created

Newsletter::subscribe()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14

Duplication

Lines 14
Ratio 100 %

Importance

Changes 0
Metric Value
dl 14
loc 14
rs 9.7998
c 0
b 0
f 0
cc 2
nc 2
nop 4
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
     *  Get all the members from a list, trying to recover from failure (useful for large lists).
69
     *
70
     * @return array
71
     * @throws \Exception thrown by Mailchimp API
72
     * @throws \DomainException if we can't get a valid result
73
     * */
74
    public function getAllMembers(string $listName = '', array $parameters = []): array
75
    {
76
        $total = $this->getMembers($listName, $parameters)['total_items'];
77
78
        $members = [];
79
80
        for ($i = 0; $i < $total; $i += 500) {
81
            $payload = array_merge($parameters, ['count'  => 500, 'offset' => $i]);
82
83
            $members = array_merge(
84
                $members,
85
                $this->retry(function () use ($payload, $listName) {
86
                    $members = $this->getMembers($listName, $payload);
87
88
                    if (! is_array($members) || ! isset($members['members'])) {
89
                        throw new \DomainException($this->getLastError());
90
                    }
91
92
                    return $members['members'];
93
                })
94
            );
95
        }
96
97
        return $members;
98
    }
99
100
    public function getMember(string $email, string $listName = '')
101
    {
102
        $list = $this->lists->findByName($listName);
103
104
        return $this->mailChimp->get("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}");
105
    }
106
107
    public function getMemberActivity(string $email, string $listName = '')
108
    {
109
        $list = $this->lists->findByName($listName);
110
111
        return $this->mailChimp->get("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}/activity");
112
    }
113
114
    public function hasMember(string $email, string $listName = ''): bool
115
    {
116
        $response = $this->getMember($email, $listName);
117
118
        if (! isset($response['email_address'])) {
119
            return false;
120
        }
121
122
        if (strtolower($response['email_address']) != strtolower($email)) {
123
            return false;
124
        }
125
126
        return true;
127
    }
128
129
    public function isSubscribed(string $email, string $listName = ''): bool
130
    {
131
        $response = $this->getMember($email, $listName);
132
133
        if (! isset($response)) {
134
            return false;
135
        }
136
137
        if ($response['status'] != 'subscribed') {
138
            return false;
139
        }
140
141
        return true;
142
    }
143
144 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...
145
    {
146
        $list = $this->lists->findByName($listName);
147
148
        $response = $this->mailChimp->patch("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}", [
149
            'status' => 'unsubscribed',
150
        ]);
151
152
        if (! $this->lastActionSucceeded()) {
153
            return false;
154
        }
155
156
        return $response;
157
    }
158
159 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...
160
    {
161
        $list = $this->lists->findByName($listName);
162
163
        $response = $this->mailChimp->patch("lists/{$list->getId()}/members/{$this->getSubscriberHash($currentEmailAddress)}", [
164
            'email_address' => $newEmailAddress,
165
        ]);
166
167
        return $response;
168
    }
169
170
    public function delete(string $email, string $listName = '')
171
    {
172
        $list = $this->lists->findByName($listName);
173
174
        $response = $this->mailChimp->delete("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}");
175
176
        return $response;
177
    }
178
179
    public function getTags(string $email, string $listName = '')
180
    {
181
        $list = $this->lists->findByName($listName);
182
183
        return $this->mailChimp->get("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}/tags");
184
    }
185
186 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...
187
    {
188
        $list = $this->lists->findByName($listName);
189
190
        $payload = collect($tags)->mapWithKeys(function ($tag) {
191
            return [$tag => 'active'];
192
        })->toArray();
193
194
        return $this->mailChimp->post("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}/tags", [
195
            'tags' => $payload,
196
        ]);
197
    }
198
199 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...
200
    {
201
        $list = $this->lists->findByName($listName);
202
203
        $payload = collect($tags)->mapWithKeys(function ($tag) {
204
            return [$tag => 'inactive'];
205
        })->toArray();
206
207
        return $this->mailChimp->post("lists/{$list->getId()}/members/{$this->getSubscriberHash($email)}/tags", [
208
            'tags' => $payload,
209
        ]);
210
    }
211
212
    public function createCampaign(
213
        string $fromName,
214
        string $replyTo,
215
        string $subject,
216
        string $html = '',
217
        string $listName = '',
218
        array $options = [],
219
        array $contentOptions = [])
220
    {
221
        $list = $this->lists->findByName($listName);
222
223
        $defaultOptions = [
224
            'type' => 'regular',
225
            'recipients' => [
226
                'list_id' => $list->getId(),
227
            ],
228
            'settings' => [
229
                'subject_line' => $subject,
230
                'from_name' => $fromName,
231
                'reply_to' => $replyTo,
232
            ],
233
        ];
234
235
        $options = array_merge($defaultOptions, $options);
236
237
        $response = $this->mailChimp->post('campaigns', $options);
238
239
        if (! $this->lastActionSucceeded()) {
240
            return false;
241
        }
242
243
        if ($html === '') {
244
            return $response;
245
        }
246
247
        if (! $this->updateContent($response['id'], $html, $contentOptions)) {
248
            return false;
249
        }
250
251
        return $response;
252
    }
253
254
    public function updateContent(string $campaignId, string $html, array $options = [])
255
    {
256
        $defaultOptions = compact('html');
257
258
        $options = array_merge($defaultOptions, $options);
259
260
        $response = $this->mailChimp->put("campaigns/{$campaignId}/content", $options);
261
262
        if (! $this->lastActionSucceeded()) {
263
            return false;
264
        }
265
266
        return $response;
267
    }
268
269
    public function getApi(): MailChimp
270
    {
271
        return $this->mailChimp;
272
    }
273
274
    /**
275
     * @return array|false
276
     */
277
    public function getLastError()
278
    {
279
        return $this->mailChimp->getLastError();
280
    }
281
282
    public function lastActionSucceeded(): bool
283
    {
284
        return $this->mailChimp->success();
285
    }
286
287
    protected function getSubscriberHash(string $email): string
288
    {
289
        return $this->mailChimp->subscriberHash($email);
290
    }
291
292
    protected function getSubscriptionOptions(string $email, array $mergeFields, array $options): array
293
    {
294
        $defaultOptions = [
295
            'email_address' => $email,
296
            'status' => 'subscribed',
297
            'email_type' => 'html',
298
        ];
299
300
        if (count($mergeFields)) {
301
            $defaultOptions['merge_fields'] = $mergeFields;
302
        }
303
304
        $options = array_merge($defaultOptions, $options);
305
306
        return $options;
307
    }
308
309
    private function retry($callback, int $max = 10)
310
    {
311
        while ($max-- > 0) {
312
            try {
313
                return $callback();
314
            } catch (Exception $e) {
315
                sleep(10);
316
            }
317
        }
318
319
        throw($e);
320
    }
321
}
322