GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — develop ( bc6f06...6b0db3 )
by Jasper
02:14
created

PayloadBuilder::buildRecipient()   B

Complexity

Conditions 6
Paths 32

Size

Total Lines 32
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 32
c 0
b 0
f 0
ccs 18
cts 18
cp 1
rs 8.439
cc 6
eloc 19
nc 32
nop 6
crap 6
1
<?php
2
3
/**
4
 * @license https://github.com/f500/swiftmailer-sparkpost/blob/master/LICENSE MIT
5
 */
6
7
namespace SwiftSparkPost;
8
9
use Swift_Attachment;
10
use Swift_Mime_Header;
11
use Swift_Mime_Message;
12
use Swift_MimePart;
13
14
/**
15
 * @copyright Future500 B.V.
16
 * @author    Jasper N. Brouwer <[email protected]>
17
 */
18
final class PayloadBuilder implements PayloadBuilderInterface
19
{
20
    /**
21
     * @param Swift_Mime_Message $message
22
     *
23
     * @return array
24
     */
25 27
    public function buildPayload(Swift_Mime_Message $message)
26
    {
27
        $payload = [
28 27
            'recipients' => $this->buildRecipients($message),
29 24
            'content'    => $this->buildContent($message),
30 8
        ];
31
32 24
        if ($campaignId = $this->buildCampaignId($message)) {
33 3
            $payload['campaign_id'] = $campaignId;
34 1
        }
35
36 24
        if ($metadata = $this->buildMetadata($message)) {
37 3
            $payload['metadata'] = $metadata;
38 1
        }
39
40 24
        if ($substitutionData = $this->buildSubstitutionData($message)) {
41 3
            $payload['substitution_data'] = $substitutionData;
42 1
        }
43
44 24
        if ($options = $this->buildOptions($message)) {
45 21
            $payload['options'] = $options;
46 7
        }
47
48 24
        return $payload;
49
    }
50
51
    /**
52
     * @param Swift_Mime_Message $message
53
     *
54
     * @return array
55
     * @throws Exception
56
     */
57 27
    private function buildRecipients(Swift_Mime_Message $message)
58
    {
59 27
        $tos = array_merge((array) $message->getTo(), (array) $message->getCc());
60 27
        $bcc = (array) $message->getBcc();
61
62 27
        if (!$tos) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $tos of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
63 3
            throw new Exception('Cannot send message without a recipient address');
64
        }
65
66 24
        $tags             = [];
67 24
        $metadata         = [];
68 24
        $substitutionData = [];
69
70 24
        if ($message instanceof Message) {
71 21
            $tags             = $message->getPerRecipientTags();
72 21
            $metadata         = $message->getPerRecipientMetadata();
73 21
            $substitutionData = $message->getPerRecipientSubstitutionData();
74 7
        }
75
76 24
        foreach ($tos as $email => $name) {
77 24
            $recipients[] = $this->buildRecipient($email, $name, $tags, $metadata, $substitutionData);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$recipients was never initialized. Although not strictly required by PHP, it is generally a good practice to add $recipients = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
78 8
        }
79
80 24
        $originalEmail = current($recipients)['address']['email'];
0 ignored issues
show
Bug introduced by
The variable $recipients does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
81
82 24
        foreach ($bcc as $email => $name) {
83 15
            $recipients[] = $this->buildRecipient($email, $name, $tags, $metadata, $substitutionData, $originalEmail);
84 8
        }
85
86 24
        return $recipients;
87
    }
88
89
    /**
90
     * @param string      $email
91
     * @param string      $name
92
     * @param array       $tags
93
     * @param array       $metadata
94
     * @param array       $substitutionData
95
     * @param string|null $originalEmail
96
     *
97
     * @return array
98
     */
99 24
    private function buildRecipient(
100
        $email,
101
        $name,
102
        array $tags,
103
        array $metadata,
104
        array $substitutionData,
105
        $originalEmail = null
106
    ) {
107 24
        $recipient = ['address' => ['email' => $email]];
108
109 24
        if ($name) {
110 9
            $recipient['address']['name'] = $name;
111 3
        }
112
113 24
        if ($originalEmail) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $originalEmail of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
114 15
            $recipient['address']['header_to'] = $originalEmail;
115 5
        }
116
117 24
        if (isset($tags[$email])) {
118 3
            $recipient['tags'] = $tags[$email];
119 1
        }
120
121 24
        if (isset($metadata[$email])) {
122 3
            $recipient['metadata'] = $metadata[$email];
123 1
        }
124
125 24
        if (isset($substitutionData[$email])) {
126 3
            $recipient['substitution_data'] = $substitutionData[$email];
127 1
        }
128
129 24
        return $recipient;
130
    }
131
132
    /**
133
     * @param Swift_Mime_Message $message
134
     *
135
     * @return array
136
     */
137 24
    private function buildContent(Swift_Mime_Message $message)
138
    {
139
        $content = [
140 24
            'subject' => $this->convertAsteriskPipeToCurlyBraces($message->getSubject()),
141 24
            'from'    => $this->buildFrom($message),
142 8
        ];
143
144 24
        if ($message->getReplyTo()) {
145 15
            $content['reply_to'] = key($message->getReplyTo());
146 5
        }
147
148 24
        $contentMap = ['text/html' => 'html', 'text/plain' => 'text'];
149
150 24
        $contentType = $this->readUserContentType($message);
151 24
        if (isset($contentMap[$contentType])) {
152 24
            $content[$contentMap[$contentType]] = $this->convertAsteriskPipeToCurlyBraces($message->getBody());
153 8
        }
154
155 24
        foreach ($message->getChildren() as $part) {
156 6
            if (!($part instanceof Swift_MimePart)) {
157 3
                continue;
158
            }
159
160 6
            $contentType = $part->getContentType();
161 6
            if (isset($contentMap[$contentType])) {
162 6
                $content[$contentMap[$contentType]] = $this->convertAsteriskPipeToCurlyBraces($part->getBody());
163 2
            }
164 8
        }
165
166 24
        if ($headers = $this->buildHeaders($message)) {
167 3
            $content['headers'] = $headers;
168 1
        }
169
170 24
        if ($attachments = $this->buildAttachments($message)) {
171 3
            $content['attachments'] = $attachments;
172 1
        }
173
174 24
        return $content;
175
    }
176
177
    /**
178
     * @param Swift_Mime_Message $message
179
     *
180
     * @return array|string
181
     */
182 24
    private function buildFrom(Swift_Mime_Message $message)
183
    {
184 24
        $from = $message->getFrom();
185
186 24
        if (current($from)) {
187 9
            return ['email' => key($from), 'name' => current($from)];
188
        }
189
190 15
        return key($from);
191
    }
192
193
    /**
194
     * @param Swift_Mime_Message $message
195
     *
196
     * @return array
197
     */
198 24
    private function buildHeaders(Swift_Mime_Message $message)
199
    {
200 24
        $headers = [];
201
        $filter  = [
202 24
            'Bcc',
203 8
            'Cc',
204 8
            'Content-Transfer-Encoding',
205 8
            'Content-Type',
206 8
            'Date',
207 8
            'DKIM-Signature',
208 8
            'DomainKey-Signature',
209 8
            'From',
210 8
            'Message-ID',
211 8
            'MIME-Version',
212 8
            'Received',
213 8
            'Reply-To',
214 8
            'Return-Path',
215 8
            'Sender',
216 8
            'Subject',
217 8
            'To',
218 8
        ];
219
220
        /** @var Swift_Mime_Header $header */
221 24
        foreach ($message->getHeaders()->getAll() as $header) {
222 24
            if (in_array($header->getFieldName(), $filter, true)) {
223 24
                continue;
224
            }
225
226 3
            $headers[] = trim($header->toString());
227 8
        }
228
229 24
        return $headers;
230
    }
231
232
    /**
233
     * @param Swift_Mime_Message $message
234
     *
235
     * @return array
236
     */
237 24
    private function buildAttachments(Swift_Mime_Message $message)
238
    {
239 24
        $attachments = [];
240
241 24
        foreach ($message->getChildren() as $part) {
242 6
            if ($part instanceof Swift_Attachment) {
243 3
                $attachments[] = [
244 3
                    'type' => $part->getContentType(),
245 3
                    'name' => $part->getFilename(),
246 5
                    'data' => base64_encode($part->getBody()),
247
                ];
248 1
            }
249 8
        }
250
251 24
        return $attachments;
252
    }
253
254
    /**
255
     * @param Swift_Mime_Message $message
256
     *
257
     * @return string
258
     */
259 24
    private function buildCampaignId(Swift_Mime_Message $message)
260
    {
261 24
        if (!($message instanceof Message)) {
262 3
            return '';
263
        }
264
265 21
        return $message->getCampaignId();
266
    }
267
268
    /**
269
     * @param Swift_Mime_Message $message
270
     *
271
     * @return array
272
     */
273 24
    private function buildMetadata(Swift_Mime_Message $message)
274
    {
275 24
        if (!($message instanceof Message)) {
276 3
            return [];
277
        }
278
279 21
        return $message->getMetadata();
280
    }
281
282
    /**
283
     * @param Swift_Mime_Message $message
284
     *
285
     * @return array
286
     */
287 24
    private function buildSubstitutionData(Swift_Mime_Message $message)
288
    {
289 24
        if (!($message instanceof Message)) {
290 3
            return [];
291
        }
292
293 21
        return $message->getSubstitutionData();
294
    }
295
296
    /**
297
     * @param Swift_Mime_Message $message
298
     *
299
     * @return array
300
     */
301 24
    private function buildOptions(Swift_Mime_Message $message)
302
    {
303 24
        if (!($message instanceof Message)) {
304 3
            return [];
305
        }
306
307 21
        return $message->getOptions();
308
    }
309
310
    /**
311
     * Convert *|foo|* to {{foo}}
312
     *
313
     * @param string
314
     *
315
     * @return string
316
     */
317 24
    private function convertAsteriskPipeToCurlyBraces($content)
318
    {
319 24
        return preg_replace('/\*\|(.+?)\|\*/', '{{\1}}', $content);
320
    }
321
322
    /**
323
     * @param Swift_Mime_Message $message
324
     *
325
     * @return string
326
     */
327 24
    private function readUserContentType(Swift_Mime_Message $message)
328
    {
329 24
        $ro = new \ReflectionObject($message);
330 24
        $rp = $ro->getProperty('_userContentType');
331 24
        $rp->setAccessible(true);
332 24
        return (string) $rp->getValue($message);
333
    }
334
}
335