PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/net/mail/transport/adapter/Debug.php

https://github.com/eLod/li3_mailer
PHP | 197 lines | 112 code | 7 blank | 78 comment | 13 complexity | 67e54b2e6905ba983453f5180e4698d0 MD5 | raw file
  1. <?php
  2. namespace li3_mailer\net\mail\transport\adapter;
  3. use lithium\core\Libraries;
  4. use lithium\util\String;
  5. use Closure;
  6. use RuntimeException;
  7. /**
  8. * The `Debug` adapter does not send email messages, but logs them to a file.
  9. *
  10. * An example configuration:
  11. * {{{Delivery::config(array('debug' => array(
  12. * 'adapter' => 'Debug',
  13. * 'from' => 'my@address',
  14. * 'log' => '/path/to/log',
  15. * 'format' => 'custom',
  16. * 'formats' => array(
  17. * 'custom' => 'Custom log for {:to}, {:subject}'
  18. * )
  19. * )));}}}
  20. * Apart from message parameters (like `'from'`, `'to'`, etc.) for supported
  21. * options see `deliver()`.
  22. *
  23. * @see li3_mailer\net\mail\transport\adapter\Debug::deliver()
  24. * @see li3_mailer\net\mail\Delivery
  25. */
  26. class Debug extends \li3_mailer\net\mail\Transport {
  27. /**
  28. * Log a message.
  29. *
  30. * @see li3_mailer\net\mail\transport\adapter\Debug::_format()
  31. * @param object $message The message to log.
  32. * @param array $options Options supported:
  33. * - `'log'` _string_ or _resource_: Path to the log file or
  34. * directory. If points to a file entries will be appended to this
  35. * file, if points to directory every message will be logged to a
  36. * new file in this directory (with a unique name generated with
  37. * `time()` and `uniqid()`).
  38. * Alternatively it may be a resource. Defaults to
  39. * `'/tmp/logs/mail.log'` relative to application's resources.
  40. * - `'format'` _string_: formatter name, defaults to `'normal'`,
  41. * see `_format()`.
  42. * @return boolean Returns `true` if the message was successfully logged,
  43. * `false` otherwise.
  44. */
  45. public function deliver($message, array $options = array()) {
  46. $options = $this->_config + $options + array(
  47. 'log' => Libraries::get(true, 'resources') . '/tmp/logs/mail.log',
  48. 'format' => 'normal'
  49. );
  50. $entry = $this->_format($message, $options['format']);
  51. $entry = '[' . date('c') . '] ' . $entry . PHP_EOL;
  52. $log = $options['log'];
  53. if (!is_resource($log)) {
  54. if (is_dir($log)) {
  55. $log .= DIRECTORY_SEPARATOR . time() . uniqid() . '.mail';
  56. }
  57. $log = fopen($log , 'a+');
  58. }
  59. $result = fwrite($log, $entry);
  60. if (!is_resource($options['log'])) {
  61. fclose($log);
  62. }
  63. return $result !== false && $result === strlen($entry);
  64. }
  65. /**
  66. * Format a message with formatter.
  67. *
  68. * @see li3_mailer\net\mail\transport\adapter\Debug::_formatters()
  69. * @param object $message Message to format.
  70. * @param string $format Formatter name to use.
  71. * @return string Formatted log entry.
  72. */
  73. protected function _format($message, $format) {
  74. $formatters = $this->_formatters();
  75. $formatter = isset($formatters[$format]) ? $formatters[$format] : null;
  76. switch (true) {
  77. case $formatter instanceof Closure:
  78. return $formatter($message);
  79. case is_string($formatter):
  80. $data = $this->_messageData($message);
  81. return String::insert($formatter, $data);
  82. default:
  83. $error = "Formatter for format `{$format}` " .
  84. "is neither string nor closure.";
  85. throw new RuntimeException($error);
  86. }
  87. }
  88. /**
  89. * Helper method for getting log formatters indexed by name. Values may be
  90. * `String::insert()` style strings (receiving the `Message`'s properties
  91. * as data according to `_messageData()`) or closures (receiving the
  92. * `Message` as the argument and should return a string that will be placed
  93. * in the log).
  94. * Additional formatters may be added with configuration key `'formats'`.
  95. *
  96. * @see li3_mailer\net\mail\transport\adapter\Debug::_messageData()
  97. * @see li3_mailer\net\mail\transport\adapter\Debug::_format()
  98. * @see lithium\util\String::insert()
  99. * @return array Available formatters indexed by name.
  100. */
  101. protected function _formatters() {
  102. $config = $this->_config + array('formats' => array());
  103. return (array) $config['formats'] + array(
  104. 'short' => 'Sent to {:to} with subject `{:subject}`.',
  105. 'normal' => "Mail sent to {:to} from {:from}" .
  106. " (sender: {:sender}, cc: {:cc}, bcc: {:bcc})\n" .
  107. "with date {:date} and subject `{:subject}`" .
  108. " in formats {:types}," .
  109. " text message body:\n{:body_text}\n",
  110. 'full' => "Mail sent to {:to} from {:from}" .
  111. " (sender: {:sender}, cc: {:cc}, bcc: {:bcc})\n" .
  112. "with date {:date} and subject `{:subject}`" .
  113. " in formats {:types}," .
  114. " text message body:\n{:body_text}\n" .
  115. "html message body:\n{:body_html}\n",
  116. 'verbose' => function($message) {
  117. $properties = var_export(get_object_vars($message), true);
  118. return "Mail sent with properties:\n{$properties}";
  119. }
  120. );
  121. }
  122. /**
  123. * Helper method to get message property data for `String::insert()`
  124. * style formatters. Additional data may be added with the
  125. * configuration key `'messageData'`, which should be an array of:
  126. *
  127. * - strings: property names (with integer keys) or the special
  128. * `'address'` value with the property name as the key (in which
  129. * case the property will be transformed with `address()`).
  130. * - closures: the keys should be property names, the closure
  131. * receives the message's property as the first argument and
  132. * should return altered data. If the key is `''` the closure will
  133. * receive the message object as the first argument and should
  134. * return an array which will be merged into the data array.
  135. *
  136. * @see li3_mailer\net\mail\transport\adapter\Debug::_formatters()
  137. * @see li3_mailer\net\mail\transport\adapter\Debug::_format()
  138. * @see li3_mailer\net\mail\Message
  139. * @param object $message Message.
  140. * @return array Message data.
  141. */
  142. protected function _messageData($message) {
  143. $config = $this->_config + array('messageData' => array());
  144. $map = (array) $config['messageData'] + array(
  145. 'subject', 'charset', 'returnPath', 'sender' => 'address',
  146. 'from' => 'address', 'replyTo' => 'address', 'to' => 'address',
  147. 'cc' => 'address', 'bcc' => 'address',
  148. 'date' => function($time) { return date('Y-m-d H:i:s', $time); },
  149. 'types' => function($types) { return join(', ', $types); },
  150. 'headers' => function($headers) { return join(PHP_EOL, $headers); },
  151. 'body' => function($bodies) {
  152. return join(PHP_EOL, array_map(function($body) {
  153. return join(PHP_EOL, $body);
  154. }, $bodies));
  155. },
  156. '' => function($message) {
  157. return array_combine(
  158. array_map(function($type) {
  159. return "body_{$type}";
  160. }, $message->types),
  161. array_map(function($type) use ($message) {
  162. return $message->body($type);
  163. }, $message->types)
  164. );
  165. }
  166. );
  167. $data = array();
  168. foreach ($map as $prop => $config) {
  169. if ($prop === '') {
  170. continue;
  171. }
  172. if (is_int($prop)) {
  173. $prop = $config;
  174. $config = null;
  175. }
  176. $value = $message->$prop;
  177. if ($config instanceof Closure) {
  178. $value = $config($value);
  179. } else if ($config === 'address') {
  180. $value = $this->_address($value);
  181. }
  182. $data[$prop] = $value;
  183. }
  184. if (isset($map['']) && $map[''] instanceof Closure) {
  185. $data = $map['']($message) + $data;
  186. }
  187. return $data;
  188. }
  189. }
  190. ?>