Completed
Push — 5.x ( 9acd44...801190 )
by Lars
06:05
created

Swift_Mime_SimpleHeaderSet   C

Complexity

Total Complexity 57

Size/Duplication

Total Lines 443
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 79.86%

Importance

Changes 11
Bugs 3 Features 1
Metric Value
c 11
b 3
f 1
dl 0
loc 443
ccs 115
cts 144
cp 0.7986
rs 6.433
wmc 57
lcom 1
cbo 3

27 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 2
A setCharset() 0 8 2
A addMailboxHeader() 0 4 1
A addDateHeader() 0 4 1
A addTextHeader() 0 4 1
A addParameterizedHeader() 0 4 1
A addIdHeader() 0 4 1
A has() 0 10 2
A set() 0 4 1
A get() 0 8 2
A getAll() 0 18 4
A remove() 0 12 3
A removeAll() 0 5 1
A newInstance() 0 4 1
A charsetChanged() 0 4 1
A __toString() 0 4 1
A _storeHeader() 0 14 3
A _canSort() 0 4 1
A _notifyHeadersOfCharset() 0 9 3
A addPathHeader() 0 4 1
A listAll() 0 9 2
A defineOrdering() 0 4 1
A setAlwaysDisplayed() 0 4 1
B toString() 0 18 6
B _sortHeaders() 0 20 9
A _isDisplayed() 0 8 2
A __clone() 0 10 3

How to fix   Complexity   

Complex Class

Complex classes like Swift_Mime_SimpleHeaderSet 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 Swift_Mime_SimpleHeaderSet, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of SwiftMailer.
5
 * (c) 2004-2009 Chris Corbyn
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
/**
12
 * A collection of MIME headers.
13
 *
14
 * @author Chris Corbyn
15
 */
16
class Swift_Mime_SimpleHeaderSet implements Swift_Mime_HeaderSet
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
17
{
18
    /**
19
     * HeaderFactory
20
     *
21
     * @var Swift_Mime_HeaderFactory
22
     */
23
    private $_factory;
24
25
    /**
26
     * Collection of set Headers
27
     *
28
     * @var array[]
29
     */
30
    private $_headers = array();
31
32
    /**
33
     * Field ordering details
34
     *
35
     * @var array
36
     */
37
    private $_order = array();
38
39
    /**
40
     * List of fields which are required to be displayed
41
     *
42
     * @var array
43
     */
44
    private $_required = array();
45
46
    /**
47
     * The charset used by Headers
48
     */
49
    private $_charset;
50
51
    /**
52
     * Create a new SimpleHeaderSet with the given $factory.
53
     *
54
     * @param Swift_Mime_HeaderFactory $factory
55
     * @param string                   $charset
56
     */
57 190
    public function __construct(Swift_Mime_HeaderFactory $factory, $charset = null)
58
    {
59 190
        $this->_factory = $factory;
60 190
        if (isset($charset)) {
61 44
            $this->setCharset($charset);
62 44
        }
63 190
    }
64
65
    /**
66
     * Set the charset used by these headers.
67
     *
68
     * @param string $charset
69
     */
70 47
    public function setCharset($charset)
71
    {
72 47
        if ($charset) {
73 47
            $this->_charset = $charset;
74 47
            $this->_factory->charsetChanged($charset);
75 47
            $this->_notifyHeadersOfCharset($charset);
76 47
        }
77 47
    }
78
79
    /**
80
     * Add a new Mailbox Header with a list of $addresses.
81
     *
82
     * @param string       $name
83
     * @param array|string $addresses
84
     */
85 2
    public function addMailboxHeader($name, $addresses = null)
86
    {
87 2
        $this->_storeHeader($name, $this->_factory->createMailboxHeader($name, $addresses));
88 2
    }
89
90
    /**
91
     * Add a new Date header using $timestamp (UNIX time).
92
     *
93
     * @param string $name
94
     * @param int    $timestamp
95
     */
96 2
    public function addDateHeader($name, $timestamp = null)
97
    {
98 2
        $this->_storeHeader($name, $this->_factory->createDateHeader($name, $timestamp));
99 2
    }
100
101
    /**
102
     * Add a new basic text header with $name and $value.
103
     *
104
     * @param string $name
105
     * @param string $value
106
     */
107 157
    public function addTextHeader($name, $value = null)
108
    {
109 157
        $this->_storeHeader($name, $this->_factory->createTextHeader($name, $value));
110 157
    }
111
112
    /**
113
     * Add a new ParameterizedHeader with $name, $value and $params.
114
     *
115
     * @param string $name
116
     * @param string $value
117
     * @param array  $params
118
     */
119 2
    public function addParameterizedHeader($name, $value = null, $params = array())
120
    {
121 2
        $this->_storeHeader($name, $this->_factory->createParameterizedHeader($name, $value, $params));
122 2
    }
123
124
    /**
125
     * Add a new ID header for Message-ID or Content-ID.
126
     *
127
     * @param string       $name
128
     * @param string|array $ids
129
     */
130 19
    public function addIdHeader($name, $ids = null)
131
    {
132 19
        $this->_storeHeader($name, $this->_factory->createIdHeader($name, $ids));
133 19
    }
134
135
    /**
136
     * Add a new Path header with an address (path) in it.
137
     *
138
     * @param string $name
139
     * @param string $path
140
     */
141 2
    public function addPathHeader($name, $path = null)
142
    {
143 2
        $this->_storeHeader($name, $this->_factory->createPathHeader($name, $path));
144 2
    }
145
146
    /**
147
     * Returns true if at least one header with the given $name exists.
148
     *
149
     * If multiple headers match, the actual one may be specified by $index.
150
     *
151
     * @param string $name
152
     * @param int    $index
153
     *
154
     * @return bool
155
     */
156 171
    public function has($name, $index = 0)
157
    {
158 171
        $lowerName = Swift::strtolowerWithStaticCache($name);
159
160 171
        if (isset($this->_headers[$lowerName], $this->_headers[$lowerName][$index])) {
161 21
            return true;
162
        } else {
163 156
            return false;
164
        }
165
    }
166
167
    /**
168
     * Set a header in the HeaderSet.
169
     *
170
     * The header may be a previously fetched header via {@link get()} or it may
171
     * be one that has been created separately.
172
     *
173
     * If $index is specified, the header will be inserted into the set at this
174
     * offset.
175
     *
176
     * @param Swift_Mime_Header $header
177
     * @param int               $index
178
     */
179 1
    public function set(Swift_Mime_Header $header, $index = 0)
180
    {
181 1
        $this->_storeHeader($header->getFieldName(), $header, $index);
182 1
    }
183
184
    /**
185
     * Get the header with the given $name.
186
     *
187
     * If multiple headers match, the actual one may be specified by $index.
188
     * Returns NULL if none present.
189
     *
190
     * @param string $name
191
     * @param int    $index
192
     *
193
     * @return Swift_Mime_Header
194
     */
195 4
    public function get($name, $index = 0)
196
    {
197 4
        if ($this->has($name, $index)) {
198 3
            $lowerName = Swift::strtolowerWithStaticCache($name);
199
200 3
            return $this->_headers[$lowerName][$index];
201
        }
202 1
    }
203
204
    /**
205
     * Get all headers with the given $name.
206
     *
207
     * @param string $name
208
     *
209
     * @return array
210
     */
211 9
    public function getAll($name = null)
212
    {
213 9
        if (!isset($name)) {
214 1
            $headers = array();
215 1
            foreach ($this->_headers as $collection) {
216 1
                $headers = array_merge($headers, $collection);
217 1
            }
218
219 1
            return $headers;
220
        }
221
222 8
        $lowerName = Swift::strtolowerWithStaticCache($name);
223 8
        if (!isset($this->_headers[$lowerName])) {
224 1
            return array();
225
        }
226
227 7
        return $this->_headers[$lowerName];
228
    }
229
230
    /**
231
     * Return the name of all Headers.
232
     *
233
     * @return array
234
     */
235 5
    public function listAll()
236
    {
237 5
        $headers = $this->_headers;
238 5
        if ($this->_canSort()) {
239
            uksort($headers, array($this, '_sortHeaders'));
240
        }
241
242 5
        return array_keys($headers);
243
    }
244
245
    /**
246
     * Remove the header with the given $name if it's set.
247
     *
248
     * If multiple headers match, the actual one may be specified by $index.
249
     *
250
     * @param string $name
251
     * @param int    $index
252
     */
253 5
    public function remove($name, $index = 0)
254
    {
255 5
        $lowerName = Swift::strtolowerWithStaticCache($name);
256
257 5
        if (isset($this->_headers[$lowerName])) {
258 5
            array_splice($this->_headers[$lowerName], $index, 1);
259
260 5
            if (empty($this->_headers[$lowerName])) {
261 3
                $this->removeAll($lowerName);
262 3
            }
263 5
        }
264 5
    }
265
266
    /**
267
     * Remove all headers with the given $name.
268
     *
269
     * @param string $name
270
     */
271 5
    public function removeAll($name)
272
    {
273 5
        $lowerName = Swift::strtolowerWithStaticCache($name);
274 5
        unset($this->_headers[$lowerName]);
275 5
    }
276
277
    /**
278
     * Create a new instance of this HeaderSet.
279
     *
280
     * @return Swift_Mime_HeaderSet
281
     */
282 1
    public function newInstance()
283
    {
284 1
        return new self($this->_factory);
285
    }
286
287
    /**
288
     * Define a list of Header names as an array in the correct order.
289
     *
290
     * These Headers will be output in the given order where present.
291
     *
292
     * @param array $sequence
293
     */
294 145
    public function defineOrdering(array $sequence)
295
    {
296 145
        $this->_order = array_flip(array_map(array('Swift' => 'strtolowerWithStaticCache'), $sequence));
297
    }
298
299
    /**
300
     * Set a list of header names which must always be displayed when set.
301
     *
302
     * Usually headers without a field value won't be output unless set here.
303
     *
304
     * @param array $names
305
     */
306 1
    public function setAlwaysDisplayed(array $names)
307
    {
308 1
        $this->_required = array_flip(array_map(array('Swift' => 'strtolowerWithStaticCache'), $names));
309
    }
310
311
    /**
312
     * Notify this observer that the entity's charset has changed.
313
     *
314
     * @param string $charset
315
     */
316 1
    public function charsetChanged($charset)
317
    {
318 1
        $this->setCharset($charset);
319 1
    }
320
321
    /**
322
     * Returns a string with a representation of all headers.
323
     *
324
     * @return string
325
     */
326 2
    public function toString()
327
    {
328 2
        $string = '';
329 2
        $headers = $this->_headers;
330 2
        if ($this->_canSort()) {
331
            uksort($headers, array($this, '_sortHeaders'));
332
        }
333 2
        foreach ($headers as $collection) {
334 2
            foreach ($collection as $header) {
335
                /* @var $header Swift_Mime_Header */
336 2
                if ($this->_isDisplayed($header) || $header->getFieldBody() != '') {
337 2
                    $string .= $header->toString();
338 2
                }
339 2
            }
340 2
        }
341
342 2
        return $string;
343
    }
344
345
    /**
346
     * Returns a string representation of this object.
347
     *
348
     * @return string
349
     *
350
     * @see toString()
351
     */
352
    public function __toString()
353
    {
354
        return $this->toString();
355
    }
356
357
    /**
358
     * Save a Header to the internal collection
359
     *
360
     * @param string            $name
361
     * @param Swift_Mime_Header $header
362
     * @param null|int          $offset
363
     */
364 185
    private function _storeHeader($name, Swift_Mime_Header $header, $offset = null)
365
    {
366 185
        $lowerName = Swift::strtolowerWithStaticCache($name);
367
368 185
        if (!isset($this->_headers[$lowerName])) {
369 185
            $this->_headers[$lowerName] = array();
370 185
        }
371
372 185
        if (!isset($offset)) {
373 184
            $this->_headers[$lowerName][] = $header;
374 184
        } else {
375 1
            $this->_headers[$lowerName][$offset] = $header;
376
        }
377 185
    }
378
379
    /** Test if the headers can be sorted */
380 7
    private function _canSort()
381
    {
382 7
        return count($this->_order) > 0;
383
    }
384
385
    /**
386
     * uksort() algorithm for Header ordering
387
     *
388
     * @param string $a
389
     * @param string $b
390
     *
391
     * @return int
392
     */
393
    private function _sortHeaders($a, $b)
394
    {
395
        $lowerA = Swift::strtolowerWithStaticCache($a);
396
        $lowerB = Swift::strtolowerWithStaticCache($b);
397
        $aPos = isset($this->_order[$lowerA]) ? $this->_order[$lowerA] : -1;
398
        $bPos = isset($this->_order[$lowerB]) ? $this->_order[$lowerB] : -1;
399
400
        if (-1 === $aPos && -1 === $bPos) {
401
            // just be sure to be determinist here
402
            return $a > $b ? -1 : 1;
403
        }
404
405
        if ($aPos === -1) {
406
            return 1;
407
        } elseif ($bPos === -1) {
408
            return -1;
409
        }
410
411
        return $aPos < $bPos ? -1 : 1;
412
    }
413
414
    /**
415
     * Test if the given Header is always displayed
416
     *
417
     * @param Swift_Mime_Header $header
418
     *
419
     * @return bool
420
     */
421 2
    private function _isDisplayed(Swift_Mime_Header $header)
422
    {
423 2
        if (isset($this->_required[Swift::strtolowerWithStaticCache($header->getFieldName())])) {
424
            return true;
425
        } else {
426 2
            return false;
427
        }
428
    }
429
430
    /**
431
     * Notify all Headers of the new charset
432
     *
433
     * @param $charset
434
     */
435 47
    private function _notifyHeadersOfCharset($charset)
436
    {
437 47
        foreach ($this->_headers as $headerGroup) {
438 2
            foreach ($headerGroup as $header) {
439
                /* @var $header Swift_Mime_Header */
440 2
                $header->setCharset($charset);
441 2
            }
442 47
        }
443 47
    }
444
445
    /**
446
     * Make a deep copy of object.
447
     */
448
    public function __clone()
449
    {
450
        $this->_factory = clone $this->_factory;
451
452
        foreach ($this->_headers as $groupKey => $headerGroup) {
453
            foreach ($headerGroup as $key => $header) {
454
                $this->_headers[$groupKey][$key] = clone $header;
455
            }
456
        }
457
    }
458
}
459