HeaderFactory::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 10
c 0
b 0
f 0
dl 0
loc 21
ccs 11
cts 11
cp 1
rs 9.9332
cc 1
nc 1
nop 9
crap 1

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * This file is part of the ZBateson\MailMimeParser project.
4
 *
5
 * @license http://opensource.org/licenses/bsd-license.php BSD
6
 */
7
8
namespace ZBateson\MailMimeParser\Header;
9
10
use Psr\Log\LoggerInterface;
11
use ReflectionClass;
12
use ZBateson\MailMimeParser\Header\Consumer\AddressBaseConsumerService;
13
use ZBateson\MailMimeParser\Header\Consumer\DateConsumerService;
14
use ZBateson\MailMimeParser\Header\Consumer\GenericConsumerMimeLiteralPartService;
15
use ZBateson\MailMimeParser\Header\Consumer\IConsumerService;
16
use ZBateson\MailMimeParser\Header\Consumer\IdBaseConsumerService;
17
use ZBateson\MailMimeParser\Header\Consumer\ParameterConsumerService;
18
use ZBateson\MailMimeParser\Header\Consumer\ReceivedConsumerService;
19
use ZBateson\MailMimeParser\Header\Consumer\SubjectConsumerService;
20
use ZBateson\MailMimeParser\Header\Part\MimeTokenPartFactory;
21
22
/**
23
 * Constructs various IHeader types depending on the type of header passed.
24
 *
25
 * If the passed header resolves to a specific defined header type, it is parsed
26
 * as such.  Otherwise, a GenericHeader is instantiated and returned.  Headers
27
 * are mapped as follows:
28
 *
29
 *  - {@see AddressHeader}: From, To, Cc, Bcc, Sender, Reply-To, Resent-From,
30
 *    Resent-To, Resent-Cc, Resent-Bcc, Resent-Reply-To, Return-Path,
31
 *    Delivered-To
32
 *  - {@see DateHeader}: Date, Resent-Date, Delivery-Date, Expires, Expiry-Date,
33
 *    Reply-By
34
 *  - {@see ParameterHeader}: Content-Type, Content-Disposition, Received-SPF,
35
 *    Authentication-Results, DKIM-Signature, Autocrypt
36
 *  - {@see SubjectHeader}: Subject
37
 *  - {@see IdHeader}: Message-ID, Content-ID, In-Reply-To, References
38
 *  - {@see ReceivedHeader}: Received
39
 *
40
 * @author Zaahid Bateson
41
 */
42
class HeaderFactory
43
{
44
    protected LoggerInterface $logger;
45
46
    /**
47
     * @var IConsumerService[] array of available consumer service classes
48
     */
49
    protected array $consumerServices;
50
51
    /**
52
     * @var MimeTokenPartFactory for mime decoding.
53
     */
54
    protected MimeTokenPartFactory $mimeTokenPartFactory;
55
56
    /**
57
     * @var string[][] maps IHeader types to headers.
58
     */
59
    protected $types = [
60
        AddressHeader::class => [
61
            'from',
62
            'to',
63
            'cc',
64
            'bcc',
65
            'sender',
66
            'replyto',
67
            'resentfrom',
68
            'resentto',
69
            'resentcc',
70
            'resentbcc',
71
            'resentreplyto',
72
            'returnpath',
73
            'deliveredto',
74
        ],
75
        DateHeader::class => [
76
            'date',
77
            'resentdate',
78
            'deliverydate',
79
            'expires',
80
            'expirydate',
81
            'replyby',
82
        ],
83
        ParameterHeader::class => [
84
            'contenttype',
85
            'contentdisposition',
86
            'receivedspf',
87
            'authenticationresults',
88
            'dkimsignature',
89
            'autocrypt',
90
        ],
91
        SubjectHeader::class => [
92
            'subject',
93
        ],
94
        IdHeader::class => [
95
            'messageid',
96
            'contentid',
97
            'inreplyto',
98
            'references'
99
        ],
100
        ReceivedHeader::class => [
101
            'received'
102
        ]
103
    ];
104
105
    /**
106
     * @var string Defines the generic IHeader type to use for headers that
107
     *      aren't mapped in $types
108
     */
109
    protected $genericType = GenericHeader::class;
110
111 14
    public function __construct(
112
        LoggerInterface $logger,
113
        MimeTokenPartFactory $mimeTokenPartFactory,
114
        AddressBaseConsumerService $addressBaseConsumerService,
115
        DateConsumerService $dateConsumerService,
116
        GenericConsumerMimeLiteralPartService $genericConsumerMimeLiteralPartService,
117
        IdBaseConsumerService $idBaseConsumerService,
118
        ParameterConsumerService $parameterConsumerService,
119
        ReceivedConsumerService $receivedConsumerService,
120
        SubjectConsumerService $subjectConsumerService
121
    ) {
122 14
        $this->logger = $logger;
123 14
        $this->mimeTokenPartFactory = $mimeTokenPartFactory;
124 14
        $this->consumerServices = [
125 14
            AddressBaseConsumerService::class => $addressBaseConsumerService,
126 14
            DateConsumerService::class => $dateConsumerService,
127 14
            GenericConsumerMimeLiteralPartService::class => $genericConsumerMimeLiteralPartService,
128 14
            IdBaseConsumerService::class => $idBaseConsumerService,
129 14
            ParameterConsumerService::class => $parameterConsumerService,
130 14
            ReceivedConsumerService::class => $receivedConsumerService,
131 14
            SubjectConsumerService::class => $subjectConsumerService
132 14
        ];
133
    }
134
135
    /**
136
     * Returns the string in lower-case, and with non-alphanumeric characters
137
     * stripped out.
138
     *
139
     * @param string $header The header name
140
     * @return string The normalized header name
141
     */
142 118
    public function getNormalizedHeaderName(string $header) : string
143
    {
144 118
        return \preg_replace('/[^a-z0-9]/', '', \strtolower($header));
145
    }
146
147
    /**
148
     * Returns the name of an IHeader class for the passed header name.
149
     *
150
     * @param string $name The header name.
151
     * @return string The Fully Qualified class name.
152
     */
153 118
    private function getClassFor(string $name) : string
154
    {
155 118
        $test = $this->getNormalizedHeaderName($name);
156 118
        foreach ($this->types as $class => $matchers) {
157 118
            foreach ($matchers as $matcher) {
158 118
                if ($test === $matcher) {
159 116
                    return $class;
160
                }
161
            }
162
        }
163 102
        return $this->genericType;
164
    }
165
166
    /**
167
     * Creates an IHeader instance for the passed header name and value, and
168
     * returns it.
169
     *
170
     * @param string $name The header name.
171
     * @param string $value The header value.
172
     * @return IHeader The created header object.
173
     */
174 118
    public function newInstance(string $name, string $value) : IHeader
175
    {
176 118
        $class = $this->getClassFor($name);
177 118
        $this->logger->debug(
178 118
            'Creating {class} for header with name "{name}" and value "{value}"',
179 118
            ['class' => $class, 'name' => $name, 'value' => $value]
180 118
        );
181 118
        return $this->newInstanceOf($name, $value, $class);
182
    }
183
184
    /**
185
     * Creates an IHeader instance for the passed header name and value using
186
     * the passed IHeader class, and returns it.
187
     *
188
     * @param string $name The header name.
189
     * @param string $value The header value.
190
     * @param string $iHeaderClass The class to use for header creation
191
     * @return IHeader The created header object.
192
     */
193 120
    public function newInstanceOf(string $name, string $value, string $iHeaderClass) : IHeader
194
    {
195 120
        $ref = new ReflectionClass($iHeaderClass);
196 120
        $params = $ref->getConstructor()->getParameters();
197 120
        if ($ref->isSubclassOf(MimeEncodedHeader::class)) {
198 90
            return new $iHeaderClass(
199 90
                $name,
200 90
                $value,
201 90
                $this->logger,
202 90
                $this->mimeTokenPartFactory,
203 90
                $this->consumerServices[$params[4]->getType()->getName()]
0 ignored issues
show
Bug introduced by
The method getName() does not exist on ReflectionType. It seems like you code against a sub-type of ReflectionType such as ReflectionNamedType. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

203
                $this->consumerServices[$params[4]->getType()->/** @scrutinizer ignore-call */ getName()]
Loading history...
204 90
            );
205
        }
206 120
        return new $iHeaderClass(
207 120
            $name,
208 120
            $value,
209 120
            $this->logger,
210 120
            $this->consumerServices[$params[3]->getType()->getName()]
211 120
        );
212
    }
213
}
214