1 <?php
2
3 /*
4 * This file is part of the ICanBoogie package.
5 *
6 * (c) Olivier Laviale <olivier.laviale@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace ICanBoogie\Mailer;
13
14 /**
15 * Representation of header fields.
16 *
17 * @see http://tools.ietf.org/html/rfc5322#section-2.2
18 */
19 class Header implements \ArrayAccess, \IteratorAggregate
20 {
21 static private $mapping = [
22
23 'Content-Type' => 'ICanBoogie\Mailer\ContentTypeHeader',
24 'From' => 'ICanBoogie\Mailer\FromHeader',
25 'Reply-To' => 'ICanBoogie\Mailer\ReplyToHeader',
26 'To' => 'ICanBoogie\Mailer\ToHeader',
27 'Cc' => 'ICanBoogie\Mailer\CcHeader',
28 'Bcc' => 'ICanBoogie\Mailer\BccHeader',
29
30 ];
31
32 /**
33 * Header fields.
34 *
35 * @var array[string]mixed
36 */
37 protected $fields = [];
38
39 public function __construct(array $fields=[])
40 {
41 foreach ($fields as $field => $value)
42 {
43 $this[$field] = $value;
44 }
45 }
46
47 public function __clone()
48 {
49 foreach ($this->fields as $field => $value)
50 {
51 $this->fields[$field] = clone $value;
52 }
53 }
54
55 /**
56 * Returns the string representation of the instance.
57 *
58 * Header fields with empty string values are discarted.
59 *
60 * @return string
61 */
62 public function __toString()
63 {
64 $header = '';
65
66 foreach ($this->fields as $field => $value)
67 {
68 $value = (string) $value;
69
70 if ($value === '')
71 {
72 continue;
73 }
74
75 $header .= "$field: $value\r\n";
76 }
77
78 return $header;
79 }
80
81 /**
82 * Checks if a header field exists.
83 *
84 * @param mixed $field
85 *
86 * @return boolean
87 */
88 public function offsetExists($field)
89 {
90 return isset($this->fields[(string) $field]);
91 }
92
93 /**
94 * Returns a header.
95 *
96 * @param mixed $field
97 *
98 * @return string|null The header field value or null if it is not defined.
99 */
100 public function offsetGet($field)
101 {
102 if (isset(self::$mapping[$field]) && empty($this->fields[$field]))
103 {
104 $class = self::$mapping[$field];
105 $this->fields[$field] = $class::from(null);
106 }
107
108 return $this->offsetExists($field) ? $this->fields[$field] : null;
109 }
110
111 /**
112 * Sets a header field.
113 *
114 * Note: Setting a header field to `null` removes it, just like unset() would.
115 *
116 * @param string $field The header field to set.
117 * @param mixed $value The value of the header field.
118 */
119 public function offsetSet($field, $value)
120 {
121 if ($value === null)
122 {
123 unset($this[$field]);
124
125 return;
126 }
127
128 if (isset(self::$mapping[$field]))
129 {
130 $value = call_user_func(self::$mapping[$field] . '::from', $value);
131 }
132
133 $this->fields[$field] = $value;
134 }
135
136 /**
137 * Removes a header field.
138 */
139 public function offsetUnset($field)
140 {
141 unset($this->fields[$field]);
142 }
143
144 /**
145 * Returns an iterator for the header fields.
146 */
147 public function getIterator()
148 {
149 // TODO: sort fields
150
151 return new \ArrayIterator($this->fields);
152 }
153 }