Completed
Push — master ( 235098...068efe )
by Frederik
02:09
created

PhpMailTransport   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 139
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 83.93%

Importance

Changes 0
Metric Value
wmc 9
lcom 1
cbo 4
dl 0
loc 139
ccs 47
cts 56
cp 0.8393
rs 10
c 0
b 0
f 0

6 Methods

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