Completed
Push — 5.0 ( 068d56...47a3bd )
by Huberty
34s
created

SwiftTwigMailTemplate   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 364
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 85.71%

Importance

Changes 0
Metric Value
wmc 40
lcom 1
cbo 5
dl 0
loc 364
ccs 108
cts 126
cp 0.8571
rs 8.2608
c 0
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
C renderMail() 0 61 15
A setFromAddresses() 0 4 1
A setFromName() 0 4 1
A setToAddresses() 0 4 1
A setToName() 0 4 1
A setBccAddresses() 0 4 1
A setBccName() 0 4 1
A setCcAddresses() 0 4 1
A setCcName() 0 4 1
A setReplyToAddresses() 0 4 1
A setReplyToName() 0 4 1
A setMaxLineLength() 0 4 1
A setPriority() 0 4 1
A setReadReceiptTo() 0 4 1
A setReturnPath() 0 4 1
B removeHtml() 0 42 6
A removeElement() 0 14 2
A keepTag() 0 10 2

How to fix   Complexity   

Complex Class

Complex classes like SwiftTwigMailTemplate often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SwiftTwigMailTemplate, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace TheCodingMachine\Mail\Template;
4
5
use TheCodingMachine\Mail\SwiftMailTemplate;
6
7
class SwiftTwigMailTemplate implements SwiftMailTemplate
8
{
9
    /**
10
     * @var \Twig_Environment
11
     */
12
    protected $twigEnvironment;
13
14
    /**
15
     * @var string
16
     */
17
    protected $twigPath;
18
19
    /**
20
     * @var string|array
21
     */
22
    protected $fromAddresses;
23
24
    /**
25
     * @var string
26
     */
27
    protected $fromName = null;
28
29
    /**
30
     * @var string|array
31
     */
32
    protected $toAddresses;
33
34
    /**
35
     * @var string
36
     */
37
    protected $toName = null;
38
39
    /**
40
     * @var string|array
41
     */
42
    protected $bccAddresses;
43
44
    /**
45
     * @var string
46
     */
47
    protected $bccName = null;
48
49
    /**
50
     * @var string|array
51
     */
52
    protected $ccAddresses;
53
54
    /**
55
     * @var string
56
     */
57
    protected $ccName = null;
58
59
    /**
60
     * @var string|array
61
     */
62
    protected $replyToAddresses;
63
64
    /**
65
     * @var string
66
     */
67
    protected $replyToName = null;
68
69
    /**
70
     * @var int
71
     */
72
    protected $maxLineLength = 1000;
73
74
    /**
75
     * @var int
76
     */
77
    protected $priority;
78
79
    /**
80
     * @var string
81
     */
82
    protected $readReceiptTo;
83
84
    /**
85
     * @var string
86
     */
87
    protected $returnPath;
88
89
    /**
90
     * SwiftTwigMailGenerator constructor.
91
     *
92
     * @param \Twig_Environment $twig_Environment
93
     * @param string            $twigPath
94
     */
95 4
    public function __construct(\Twig_Environment $twig_Environment, string $twigPath)
96
    {
97 4
        $this->twigEnvironment = $twig_Environment;
98 4
        $this->twigPath = $twigPath;
99 4
    }
100
101
    /**
102
     * @param array $data
103
     *
104
     * @return \Swift_Message
105
     */
106 4
    public function renderMail(array $data = []) :\Swift_Message
107
    {
108 4
        $mail = new \Swift_Message();
109
110 4
        $twigEnvironment = clone $this->twigEnvironment;
111 4
        $function = new \Twig_SimpleFunction('embedImage', function ($imgPath) use ($mail) {
112
            return $mail->embed(\Swift_Image::fromPath($imgPath));
113 4
        });
114 4
        $twigEnvironment->addFunction($function);
115
116 4
        $template = $twigEnvironment->loadTemplate($this->twigPath);
117
118 4
        if (!$template->hasBlock('subject') || (!$template->hasBlock('body_html') && !$template->hasBlock('body_text'))) {
119 1
            throw MissingBlockException::missingBlock($template->getBlockNames());
120
        }
121
122 3
        $subject = $template->renderBlock('subject', $data);
0 ignored issues
show
Bug introduced by
The method renderBlock() does not exist on Twig_TemplateInterface. Did you maybe mean render()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
123 3
        $mail->setSubject($subject);
124
125 3
        if ($template->hasBlock('body_html')) {
126 2
            $bodyHtml = $template->renderBlock('body_html', $data);
0 ignored issues
show
Bug introduced by
The method renderBlock() does not exist on Twig_TemplateInterface. Did you maybe mean render()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
127 2
            if (!$template->hasBlock('body_text')) {
128 1
                $bodyText = $this->removeHtml($bodyHtml);
129
            } else {
130 1
                $bodyText = $template->renderBlock('body_text', $data);
0 ignored issues
show
Bug introduced by
The method renderBlock() does not exist on Twig_TemplateInterface. Did you maybe mean render()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
131
            }
132
133 2
            $mail->setBody($bodyHtml, 'text/html');
134 2
            $mail->addPart($bodyText, 'text/plain');
135
        } else {
136 1
            $bodyText = $template->renderBlock('body_text', $data);
0 ignored issues
show
Bug introduced by
The method renderBlock() does not exist on Twig_TemplateInterface. Did you maybe mean render()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
137
138 1
            $mail->setBody($bodyText, 'text/plain');
139
        }
140
141
        switch (true) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $this->maxLineLength of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing $this->priority of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing $this->readReceiptTo of type string to the boolean true. If you are specifically checking for a non-empty string, consider using the more explicit !== '' instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing $this->returnPath of type string to the boolean true. If you are specifically checking for a non-empty string, consider using the more explicit !== '' instead.
Loading history...
142 3
            case $this->fromAddresses:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
143 1
                $mail->setFrom($this->fromAddresses, $this->fromName);
144 1
                $mail->setSender($this->fromAddresses, $this->fromName);
145 2
            case $this->toAddresses:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
146 1
                $mail->setTo($this->toAddresses, $this->toName);
147 2
            case $this->bccAddresses:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
148 1
                $mail->setBcc($this->bccAddresses, $this->bccName);
149 2
            case $this->ccAddresses:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
150 1
                $mail->setCc($this->ccAddresses, $this->ccName);
151 2
            case $this->replyToAddresses:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
152 1
                $mail->setReplyTo($this->replyToAddresses, $this->replyToName);
153 2
            case $this->maxLineLength:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
154 3
                $mail->setMaxLineLength($this->maxLineLength);
155
            case $this->priority:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
156 3
                $mail->setPriority($this->priority);
157
            case $this->readReceiptTo:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
158 3
                $mail->setReadReceiptTo($this->readReceiptTo);
0 ignored issues
show
Documentation introduced by
$this->readReceiptTo is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
159
            case $this->returnPath:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
160 3
                $mail->setReturnPath($this->returnPath);
161
            default:
162 3
                break;
163
        }
164
165 3
        return $mail;
166
    }
167
168
    /**
169
     * @param array|string $fromAddresses
170
     */
171 1
    public function setFromAddresses($fromAddresses)
172
    {
173 1
        $this->fromAddresses = $fromAddresses;
174 1
    }
175
176
    /**
177
     * @param string $fromName
178
     */
179 1
    public function setFromName($fromName)
180
    {
181 1
        $this->fromName = $fromName;
182 1
    }
183
184
    /**
185
     * @param array|string $toAddresses
186
     */
187 1
    public function setToAddresses($toAddresses)
188
    {
189 1
        $this->toAddresses = $toAddresses;
190 1
    }
191
192
    /**
193
     * @param string $toName
194
     */
195 1
    public function setToName($toName)
196
    {
197 1
        $this->toName = $toName;
198 1
    }
199
200
    /**
201
     * @param array|string $bccAddresses
202
     */
203 1
    public function setBccAddresses($bccAddresses)
204
    {
205 1
        $this->bccAddresses = $bccAddresses;
206 1
    }
207
208
    /**
209
     * @param string $bccName
210
     */
211 1
    public function setBccName($bccName)
212
    {
213 1
        $this->bccName = $bccName;
214 1
    }
215
216
    /**
217
     * @param array|string $ccAddresses
218
     */
219 1
    public function setCcAddresses($ccAddresses)
220
    {
221 1
        $this->ccAddresses = $ccAddresses;
222 1
    }
223
224
    /**
225
     * @param string $ccName
226
     */
227 1
    public function setCcName($ccName)
228
    {
229 1
        $this->ccName = $ccName;
230 1
    }
231
232
    /**
233
     * @param array|string $replyToAddresses
234
     */
235 1
    public function setReplyToAddresses($replyToAddresses)
236
    {
237 1
        $this->replyToAddresses = $replyToAddresses;
238 1
    }
239
240
    /**
241
     * @param string $replyToName
242
     */
243 1
    public function setReplyToName($replyToName)
244
    {
245 1
        $this->replyToName = $replyToName;
246 1
    }
247
248
    /**
249
     * @param int $maxLineLength
250
     */
251 1
    public function setMaxLineLength($maxLineLength)
252
    {
253 1
        $this->maxLineLength = $maxLineLength;
254 1
    }
255
256
    /**
257
     * @param int $priority
258
     */
259 1
    public function setPriority($priority)
260
    {
261 1
        $this->priority = $priority;
262 1
    }
263
264
    /**
265
     * @param string $readReceiptTo
266
     */
267 1
    public function setReadReceiptTo($readReceiptTo)
268
    {
269 1
        $this->readReceiptTo = $readReceiptTo;
270 1
    }
271
272
    /**
273
     * @param string $returnPath
274
     */
275 1
    public function setReturnPath($returnPath)
276
    {
277 1
        $this->returnPath = $returnPath;
278 1
    }
279
280
    /**
281
     * Removes the HTML tags from the text.
282
     *
283
     * @param string $s
284
     * @param string $keep   The list of tags to keep
285
     * @param string $expand The list of tags to remove completely, along their content
286
     */
287 1
    private function removeHtml(string $s, string $keep = '', string $expand = 'script|style|noframes|select|option') :string
288
    {
289
        /**///prep the string
290 1
        $s = ' '.$s;
291
292
        /**///initialize keep tag logic
293 1
        if (strlen($keep) > 0) {
294
            $k = explode('|', $keep);
295
            $s = $this->keepTag($s, $k, '<', '[{(');
296
        }
297
        //begin removal
298
        /**///remove comment blocks
299 1
        $s = $this->removeElement($s, '<!--', '-->');
300
301
        /**///remove tags with content between them
302 1
        if (strlen($expand) > 0) {
303 1
            $e = explode('|', $expand);
304 1
            $count = count($e);
305 1
            $pos = [];
306 1
            $len = [];
307 1
            for ($i = 0;$i < $count;++$i) {
308 1
                while (stripos($s, '<'.$e[$i]) > 0) {
309
                    $len[1] = strlen('<'.$e[$i]);
310
                    $pos[1] = stripos($s, '<'.$e[$i]);
311
                    $pos[2] = stripos($s, $e[$i].'>', $pos[1] + $len[1]);
312
                    $len[2] = $pos[2] - $pos[1] + $len[1];
313
                    $x = substr($s, $pos[1], $len[2]);
314
                    $s = str_replace($x, '', $s);
315
                }
316
            }
317
        }
318
319
        /**///remove remaining tags
320 1
        $s = $this->removeElement($s, '<', '>');
321
322
        /**///finalize keep tag
323 1
        if (isset($k)) {
324
            $s = $this->keepTag($s, $k, '[{(', '<');
325
        }
326
327 1
        return trim($s);
328
    }
329
330
    /**
331
     * @param string $s
332
     * @param string $openTag
333
     * @param string $closeTag
334
     *
335
     * @return mixed|string
336
     */
337 1
    private function removeElement(string $s, string $openTag, string $closeTag)
338
    {
339 1
        $pos = [];
340 1
        $len = [];
341 1
        while (stripos($s, $openTag) > 0) {
342 1
            $pos[1] = stripos($s, $openTag);
343 1
            $pos[2] = stripos($s, $closeTag, $pos[1]);
344 1
            $len[1] = $pos[2] - $pos[1] + 1;
345 1
            $x = substr($s, $pos[1], $len[1]);
346 1
            $s = str_replace($x, '', $s);
347
        }
348
349 1
        return $s;
350
    }
351
352
    /**
353
     * @param string $s
354
     * @param array  $tagToKeep
355
     * @param string $initial
356
     * @param string $finalize
357
     *
358
     * @return string
359
     */
360
    private function keepTag(string $s, array $tagToKeep, string $initial, string $finalize):string
361
    {
362
        $count = count($tagToKeep);
363
        for ($i = 0;$i < $count;++$i) {
364
            $s = str_replace($initial.$tagToKeep[$i], $finalize.$tagToKeep[$i], $s);
365
            $s = str_replace($initial.'/'.$tagToKeep[$i], $finalize.'/'.$tagToKeep[$i], $s);
366
        }
367
368
        return $s;
369
    }
370
}
371