Completed
Pull Request — master (#64)
by Frederik
03:38 queued 01:09
created

PhpMailTransport::extractHeaders()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 2.0005

Importance

Changes 0
Metric Value
dl 0
loc 33
ccs 18
cts 19
cp 0.9474
rs 9.392
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2.0005
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
     * @var EnvelopeFactory
16
     */
17
    private $envelopeFactory;
18
19
    /**
20
     * @var array<int, string>
21
     */
22
    private $parameters;
23
24
    /**
25
     * @var \Closure
26
     */
27
    private $replacedMailMethod;
28
29
    /**
30
     * @param EnvelopeFactory $envelopeFactory
31
     * @param array<int, string> $parameters
32
     */
33 4
    public function __construct(EnvelopeFactory $envelopeFactory, array $parameters = [])
34
    {
35 4
        $this->envelopeFactory = $envelopeFactory;
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 1
                $to,
64
                $subject,
65 1
                (string)$message->getBody(),
66
                $headers,
67
                $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
81 4
        foreach ($headers as $header) {
82 3
            return (string)$header->getValue();
83
        }
84
85 2
        throw new \InvalidArgumentException('Cannot transport message without header ' . $name);
86
    }
87
88
    /**
89
     * @param MessageInterface $message
90
     * @return string
91
     */
92 2
    private function extractHeaders(MessageInterface $message): string
93
    {
94
        $headers = $message
95 2
            ->withoutHeader('to')
96 2
            ->withoutHeader('subject')
97 2
            ->getHeaders();
98
99 2
        if (!\is_array($headers)) {
100
            $headers = \iterator_to_array($headers);
101
        }
102
103 2
        return \implode(
104 2
            "\r\n",
105 2
            \array_values(
106 2
                \array_filter(
107 2
                    \array_map(
108
                        function (array $headers) {
109 2
                            return \implode(
110 2
                                "\r\n",
111 2
                                \array_map(
112
                                    function (HeaderInterface $header) {
113 2
                                        return (string)(new HeaderLine($header));
114 2
                                    },
115 2
                                    $headers
116
                                )
117
                            );
118 2
                        },
119 2
                        $headers
120
                    )
121
                )
122
            )
123
        );
124
    }
125
126
    /**
127
     * @param MessageInterface $message
128
     * @return string
129
     * @throws EnvelopeException
130
     */
131 2
    private function constructParameters(MessageInterface $message): string
132
    {
133 2
        $envelop = $this->envelopeFactory->make($message);
134 2
        if (\preg_match('/\"/', $envelop->getAddress())) {
135 1
            throw new EnvelopeException(
136 1
                'Unable to guarantee injection-free envelop'
137
            );
138
        }
139
140 1
        return \implode(' ', \array_merge($this->parameters, ['-f' . (string)$envelop]));
141
    }
142
143
    /**
144
     * @param \Closure $callback
145
     * @param EnvelopeFactory $envelopeFactory
146
     * @param array<int, string> $parameters
147
     * @return PhpMailTransport
148
     */
149 4
    public static function newReplaceMailMethod(
150
        \Closure $callback,
151
        EnvelopeFactory $envelopeFactory,
152
        array $parameters = []
153
    ): PhpMailTransport {
154 4
        $transport = new self($envelopeFactory, $parameters);
155 4
        $transport->replacedMailMethod = $callback;
156 4
        return $transport;
157
    }
158
}
159