Completed
Push — master ( fafa6b...d42f0d )
by Frederik
03:02
created

PhpMailTransport   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 142
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 94%

Importance

Changes 0
Metric Value
wmc 9
lcom 1
cbo 5
dl 0
loc 142
c 0
b 0
f 0
rs 10
ccs 47
cts 50
cp 0.94

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
B send() 0 28 2
A extractSingleHeader() 0 11 2
B extractHeaders() 0 26 1
A constructParameters() 0 11 2
A newReplaceMailMethod() 0 10 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Genkgo\Mail\Transport;
5
6
use Genkgo\Mail\Exception\EnvelopeException;
7
use Genkgo\Mail\Header\HeaderLine;
8
use Genkgo\Mail\HeaderInterface;
9
use Genkgo\Mail\MessageInterface;
10
use Genkgo\Mail\TransportInterface;
11
12
final class PhpMailTransport implements TransportInterface
13
{
14
15
    /**
16
     * @var EnvelopeFactory
17
     */
18
    private $envelopFactory;
19
    /**
20
     * @var array
21
     */
22
    private $parameters;
23
    /**
24
     * @var \Closure
25
     */
26
    private $replacedMailMethod;
27
28
    /**
29
     * PhpMailTransport constructor.
30
     * @param EnvelopeFactory $envelopFactory
31
     * @param array $parameters
32
     */
33 4
    public function __construct(EnvelopeFactory $envelopFactory, array $parameters = [])
34
    {
35 4
        $this->envelopFactory = $envelopFactory;
36 4
        $this->parameters = $parameters;
37 4
    }
38
39
    /**
40
     * @param MessageInterface $message
41
     * @return void
42
     */
43 4
    public function send(MessageInterface $message): void
44
    {
45 4
        $to = $this->extractSingleHeader($message, 'to');
46 3
        $subject = $this->extractSingleHeader($message, 'subject');
47 2
        $headers = $this->extractHeaders($message);
48 2
        $parameters = $this->constructParameters($message);
49
50 1
        if ($this->replacedMailMethod === null) {
51
            // @codeCoverageIgnoreStart
52
            mail(
53
                $to,
54
                $subject,
55
                (string)$message->getBody(),
56
                $headers,
57
                $parameters
58
            );
59
            // @codeCoverageIgnoreEnd
60
        } else {
61 1
            $callback = $this->replacedMailMethod;
62 1
            $callback(
63
                $to,
64
                $subject,
65 1
                (string)$message->getBody(),
66
                $headers,
67 1
                $parameters
68
            );
69
        }
70 1
    }
71
72
    /**
73
     * @param MessageInterface $message
74
     * @param string $name
75
     * @return string
76
     */
77 4
    private function extractSingleHeader(MessageInterface $message, string $name): string
78
    {
79 4
        $headers = $message->getHeader($name);
80 4
        if (count($headers) === 0) {
81 2
            throw new \InvalidArgumentException(
82 2
                'Cannot transport message without header ' . $name
83
            );
84
        }
85
86 3
        return (string)reset($headers)->getValue();
87
    }
88
89
    /**
90
     * @param MessageInterface $message
91
     * @return string
92
     */
93 2
    private function extractHeaders(MessageInterface $message): string
94
    {
95 2
        return implode("\r\n",
96 2
            array_values(
97 2
                array_filter(
98 2
                    array_map(
99
                        function (array $headers) {
100 2
                            return implode(
101 2
                                "\r\n",
102 2
                                array_map(
103 2
                                    function (HeaderInterface $header) {
104 2
                                        return (string)(new HeaderLine($header));
105 2
                                    },
106 2
                                    $headers
107
                                )
108
                            );
109 2
                        },
110
                        $message
111 2
                            ->withoutHeader('to')
112 2
                            ->withoutHeader('subject')
113 2
                            ->getHeaders()
114
                    )
115
                )
116
            )
117
        );
118
    }
119
120
    /**
121
     * @param MessageInterface $message
122
     * @return string
123
     * @throws EnvelopeException
124
     */
125 2
    private function constructParameters(MessageInterface $message): string
126
    {
127 2
        $envelop = $this->envelopFactory->make($message);
128 2
        if (preg_match('/\"/', $envelop->getAddress())) {
129 1
            throw new EnvelopeException(
130 1
                'Unable to guarantee injection-free envelop'
131
            );
132
        }
133
134 1
        return implode(' ', array_merge($this->parameters, ['-f' . (string)$envelop]));
135
    }
136
137
    /**
138
     * @param \Closure $callback
139
     * @param EnvelopeFactory $envelopFactory
140
     * @param array $parameters
141
     * @return PhpMailTransport
142
     */
143 4
    public static function newReplaceMailMethod(
144
        \Closure $callback,
145
        EnvelopeFactory $envelopFactory,
146
        array $parameters = []
147
    ): PhpMailTransport
148
    {
149 4
        $transport = new self($envelopFactory, $parameters);
150 4
        $transport->replacedMailMethod = $callback;
151 4
        return $transport;
152
    }
153
}