Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit ce088e8924c5108750f309542806fd542ca7b2e6 @eLod eLod committed Sep 15, 2011
Showing with 4,076 additions and 0 deletions.
  1. +20 −0 LICENSE.txt
  2. +25 −0 README.md
  3. +196 −0 action/Mailer.php
  4. +38 −0 config/bootstrap.php
  5. +69 −0 config/bootstrap/delivery.php
  6. +41 −0 net/mail/Delivery.php
  7. +89 −0 net/mail/Grammar.php
  8. +355 −0 net/mail/Media.php
  9. +14 −0 net/mail/MediaException.php
  10. +634 −0 net/mail/Message.php
  11. +40 −0 net/mail/Transport.php
  12. +188 −0 net/mail/transport/adapter/Debug.php
  13. +117 −0 net/mail/transport/adapter/Simple.php
  14. +206 −0 net/mail/transport/adapter/Swift.php
  15. +188 −0 readme.wiki
  16. +63 −0 template/Mail.php
  17. +14 −0 template/helper/mail/Form.php
  18. +98 −0 template/helper/mail/Html.php
  19. +31 −0 template/mail/Compiler.php
  20. +200 −0 template/mail/adapter/File.php
  21. +107 −0 tests/cases/action/MailerTest.php
  22. +17 −0 tests/cases/net/mail/DeliveryTest.php
  23. +44 −0 tests/cases/net/mail/GrammarTest.php
  24. +148 −0 tests/cases/net/mail/MediaTest.php
  25. +233 −0 tests/cases/net/mail/MessageTest.php
  26. +21 −0 tests/cases/net/mail/TransportTest.php
  27. +144 −0 tests/cases/net/mail/transport/adapter/DebugTest.php
  28. +116 −0 tests/cases/net/mail/transport/adapter/SimpleTest.php
  29. +176 −0 tests/cases/net/mail/transport/adapter/SwiftTest.php
  30. +39 −0 tests/cases/template/MailTest.php
  31. +52 −0 tests/cases/template/helper/mail/HtmlTest.php
  32. +41 −0 tests/cases/template/mail/CompilerTest.php
  33. +109 −0 tests/cases/template/mail/adapter/FileTest.php
  34. +15 −0 tests/mocks/action/Mailer.php
  35. +11 −0 tests/mocks/action/MailerOverload.php
  36. +16 −0 tests/mocks/action/MailerWithOptions.php
  37. +8 −0 tests/mocks/action/TestMailer.php
  38. +15 −0 tests/mocks/net/mail/Delivery.php
  39. +11 −0 tests/mocks/net/mail/DeliveryWithPath.php
  40. +11 −0 tests/mocks/net/mail/Transport.php
  41. +14 −0 tests/mocks/net/mail/transport/adapter/Simple.php
  42. +13 −0 tests/mocks/net/mail/transport/adapter/Swift.php
  43. +14 −0 tests/mocks/net/mail/transport/adapter/SwiftTransport.php
  44. +26 −0 tests/mocks/template/Mail.php
  45. +11 −0 tests/mocks/template/MailWithoutRender.php
  46. +19 −0 tests/mocks/template/mail/Compiler.php
  47. +19 −0 tests/mocks/template/mail/adapter/FileLoader.php
@@ -0,0 +1,20 @@
+Copyright (c) 2011 Tamas Pozsonyi (pota@mosfet.hu)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,25 @@
+# Li3 mailer plugin
+
+A plugin for sending email messages from your li3 application.
+
+## Installation
+
+Install and register the plugin as described by [the manual](http://lithify.me/docs/manual).
+
+## Documentation
+
+The documentation was created with the [li3_docs](https://github.com/UnionOfRAD/li3_docs) plugin in mind,
+please see the readme.wiki for details.
+
+## TODO
+
+ * better documentation
+ * restructure View/Renderer/etc. (in lithium core) to better support inheritance (and support the `Simple` renderer/loader)
+
+## Credits
+
+Thanks to [nateabele](https://github.com/nateabele), [daschl](https://github.com/daschl), [masom](https://github.com/masom) and the lively [li3](http://lithify.me) community.
+
+## Copyright
+
+See LICENSE.txt for details.
@@ -0,0 +1,196 @@
+<?php
+
+namespace li3_mailer\action;
+
+use lithium\util\Inflector;
+use BadMethodCallException;
+
+/**
+ * The `Mailer` class is the fundamental building block for sending mails within your application.
+ * It may be subclassed to group options (with `$_messages`) and/or templates (view templates can
+ * reside in a folder named after their `Mailer` subclass) together.
+ *
+ * @see li3_mailer\net\mail\Media
+ * @see li3_mailer\net\mail\Delivery
+ * @see li3_mailer\action\Mailer::deliver()
+ */
+class Mailer extends \lithium\core\StaticObject {
+ /**
+ * Holds extra configurations per message (and a default
+ * for every message at key `0` if set). See `Mailer::_options()`.
+ *
+ * @see li3_mailer\action\Mailer::_options()
+ * @var array
+ */
+ protected static $_messages = array();
+
+ /**
+ * The option names that should not be treated as data when parsing
+ * options. See `Mailer::_options()`.
+ *
+ * @see li3_mailer\action\Mailer::_options()
+ * @var array
+ */
+ protected static $_short_options = array('from', 'cc', 'bcc', 'subject', 'delivery');
+
+ /**
+ * Class dependencies.
+ *
+ * @var array
+ */
+ protected static $_classes = array(
+ 'media' => 'li3_mailer\net\mail\Media',
+ 'delivery' => 'li3_mailer\net\mail\Delivery',
+ 'message' => 'li3_mailer\net\mail\Message'
+ );
+
+ /**
+ * Create a message object with given options.
+ *
+ * @see li3_mailer\net\mail\Message
+ * @param array $options Options, apart from `Message`'s options if `'class'`
+ * is presented it will be used for creating the instance, otherwise
+ * defaults to `'message'` (see `_instance()` and `$_classes`).
+ * @return li3_mailer\net\mail\Message A message instance.
+ */
+ public static function message(array $options = array()) {
+ return static::_filter(__FUNCTION__, compact('options'), function($self, $params) {
+ $options = $params['options'];
+ $class = isset($options['class']) ? $options['class'] : 'message';
+ unset($options['class']);
+ return $self::invokeMethod('_instance', array($class, $options));
+ });
+ }
+
+ /**
+ * Deliver a message. Creates a message with given options,
+ * renders it with `Media` and delivers it via the transport
+ * adapter. This method is filterable and the filter receives
+ * the (cleared) options, data, message (object), transport
+ * adapter and transport options as parameters.
+ *
+ * @see li3_mailer\action\Mailer::message()
+ * @see li3_mailer\net\mail\Message
+ * @see li3_mailer\net\mail\Media::render()
+ * @see li3_mailer\net\mail\Transport::deliver()
+ * @param string $message_name Name of the message to send.
+ * @param array $options Options may be:
+ * - options for creating the message (see `message()`),
+ * - options for rendering the message (see `Media::render()`),
+ * sets `'mailer'` (to `Mailer` subclass' short name) and
+ * `'template'` (to `$message_name`) by default,
+ * - `'transport'`: transport options (see `Transport::deliver()`),
+ * - `'data'`: binded data for rendering (see `Media::render()`),
+ * - `'delivery'`: the delivery configuration and adapter to use
+ * (configuration will be merged into options for creating the
+ * the message).
+ * @return mixed Return value of the transport adapter's deliver method.
+ */
+ public static function deliver($message_name, array $options = array()) {
+ $options = static::_options($message_name, $options);
+
+ $delivery = static::$_classes['delivery'];
+ $delivery_name = isset($options['delivery']) ? $options['delivery'] : 'default';
+ unset($options['delivery']);
+ $message_options = $options + $delivery::config($delivery_name);
+ $message = static::message($message_options);
+ $transport = $delivery::adapter($delivery_name);
+ $transport_options = isset($options['transport']) ? (array) $options['transport'] : array();
+ unset($options['transport']);
+
+ $data = isset($options['data']) ? $options['data'] : array();
+ unset($options['data']);
+ $class = get_called_class();
+ $name = preg_replace('/Mailer$/', '', substr($class, strrpos($class, "\\") + 1));
+ $options += array(
+ 'mailer' => ($name == '' ? null : Inflector::underscore($name)),
+ 'template' => $message_name
+ );
+
+ $media = static::$_classes['media'];
+ $params = compact('options', 'data', 'message', 'transport', 'transport_options');
+ return static::_filter(__FUNCTION__, $params, function($self, $params) use ($media) {
+ extract($params);
+ $media::render($message, $data, $options);
+ return $transport->deliver($message, $transport_options);
+ });
+ }
+
+ /**
+ * Allows the use of syntactic-sugar like `Mailer::deliverTestWithLocal()` instead of
+ * `Mailer::deliver('test', array('delivery' => 'local'))`.
+ *
+ * @see li3_mailer\action\Mailer::deliver()
+ * @link http://php.net/manual/en/language.oop5.overloading.php PHP Manual: Overloading
+ *
+ * @throws BadMethodCallException On unhandled call, will throw an exception.
+ * @param string $method Method name caught by `__callStatic()`.
+ * @param array $params Arguments given to the above `$method` call.
+ * @return mixed Results of dispatched `Mailer::deliver()` call.
+ */
+ public static function __callStatic($method, $params) {
+ $found = preg_match('/^deliver(?P<message>\w+)With(?P<delivery>\w+)$/', $method, $args);
+ if (!$found) {
+ preg_match('/^deliver(?P<message>\w+)$/', $method, $args);
+ }
+ if ($args) {
+ $message = Inflector::underscore($args['message']);
+ if (isset($params[0]) && is_array($params[0])) {
+ $params = $params[0];
+ }
+ if (isset($args['delivery'])) {
+ $params['delivery'] = Inflector::underscore($args['delivery']);
+ }
+ return static::deliver($message, $params);
+ } else {
+ $class = get_called_class();
+ $class = substr($class, strrpos($class, "\\") + 1);
+ throw new BadMethodCallException(
+ "Method `{$method}` not defined or handled in class `{$class}`."
+ );
+ }
+ }
+
+ /**
+ * Get options for a given message. Allows shorter options syntax
+ * where the first item does not have an associative key (e.g. the
+ * key is `0`)
+ * like `('message', array('foo@bar', 'subject' => 'my subject', 'my' => 'data'))`
+ * which will be translated to
+ * `('message', array('to' => 'foo@bar', 'subject' => 'my subject',
+ * 'data' => array('my' => 'data'))`.
+ * Uses `$_short_options` to detect options that should be extracted
+ * (unless a value for key `'data'` is already set),
+ * also merges in the settings from `$_messages`.
+ *
+ * @see li3_mailer\action\Mailer::$_messages
+ * @see li3_mailer\action\Mailer::$_short_options
+ * @param string $message The message identifier (name).
+ * @param array $options Options.
+ * @return array Options.
+ */
+ protected static function _options($message, array $options = array()) {
+ if (isset($options[0])) {
+ $to = $options[0];
+ unset($options[0]);
+ if (isset($options['data'])) {
+ $options += compact('to');
+ } else {
+ $data = $options;
+ $blank = array_fill_keys(static::$_short_options, null);
+ $shorts = array_intersect_key($data, $blank);
+ $data = array_diff_key($data, $shorts);
+ $options = compact('to', 'data') + $shorts;
+ }
+ }
+ if (array_key_exists($message, static::$_messages)) {
+ $options = array_merge_recursive((array) static::$_messages[$message], $options);
+ }
+ if (isset(static::$_messages[0])) {
+ $options = array_merge_recursive((array) static::$_messages[0], $options);
+ }
+ return $options;
+ }
+}
+
+?>
@@ -0,0 +1,38 @@
+<?php
+
+use lithium\core\Libraries;
+
+/**
+ * Register paths for mail template helpers.
+ */
+$existing = Libraries::paths('helper');
+Libraries::paths(array('helper' => array_merge(array(
+ '{:library}\extensions\helper\{:class}\{:name}',
+ '{:library}\template\helper\{:class}\{:name}' => array('libraries' => 'li3_mailer')
+), (array) $existing)));
+
+/**
+ * Add paths for delivery transport adapters from this library (plugin).
+ */
+$existing = Libraries::paths('adapter');
+$key = '{:library}\{:namespace}\{:class}\adapter\{:name}';
+$existing[$key]['libraries'] = array_merge(
+ (array) $existing[$key]['libraries'],
+ (array) 'li3_mailer'
+);
+Libraries::paths(array('adapter' => $existing));
+
+/*
+ * Ensure the mail template resources path exists.
+ */
+$path = Libraries::get(true, 'resources') . '/tmp/cache/mails';
+if (!is_dir($path)) {
+ mkdir($path);
+}
+
+/**
+ * Load the file that configures the delivery system.
+ */
+require __DIR__ . '/bootstrap/delivery.php';
+
+?>
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * ### Configure email delivery
+ *
+ * The `Delivery` is a configurable service that provides transport adapters for sending emails
+ * from your application. As with other `Adaptable`-based configurations, each delivery
+ * configuration is defined by a name, and an array of information detailing extra configuration
+ * for that delivery adapter. `Delivery` also supports environment-base configurations.
+ *
+ * By default the plugin provides 3 adapters:
+ *
+ * - `'Simple'`: uses `PHP`'s built-in `mail` function to send messages,
+ * - `'Debug'`: does not send mails, but logs them to a file,
+ * - `'Swift'`: uses the `SwiftMailer` library to send messages.
+ *
+ * For configuration options please see the adapters' documentation.
+ *
+ * Apart from the adapter options the configuration may hold settings for the messages that should
+ * be sent with this adapter, like (but not limited to) `'from'`, `'cc'` and other fields. The
+ * `Mailer` will retrieve the configuration when constructing the `Message` for delivery and set
+ * applicable values.
+ *
+ * @see li3_mailer\net\mail\Delivery
+ * @see lithium\core\Adaptable
+ * @see li3_mailer\net\mail\Transport
+ * @see li3_mailer\net\mail\transport\adapter\Simple
+ * @see li3_mailer\net\mail\transport\adapter\Debug
+ * @see li3_mailer\net\mail\transport\adapter\Swift
+ * @see li3_mailer\net\mail\Message
+ * @see li3_mailer\net\mail\Mailer
+ * @see li3_mailer\net\mail\Mailer::deliver()
+ */
+use li3_mailer\net\mail\Delivery;
+
+/**
+ * Sample configuration for `'Simple'` adapter
+ */
+// Delivery::config(array('default' => array(
+// 'adapter' => 'Simple',
+// 'from' => array('My App' => 'my@email.address')
+// )));
+
+/**
+ * Sample configuration for `'Swift'` adapter
+ */
+// Delivery::config(array('default' => array(
+// 'adapter' => 'Swift',
+// 'transport' => 'smtp',
+// 'from' => array('Name' => 'my@address'),
+// 'host' => 'example.host',
+// 'encryption' => 'ssl'
+// )));
+
+/**
+ * ### SwiftMailer support
+ *
+ * To use the `'Swift'` adapter with the plugin the SwiftMailer library must be register first.
+ * To install the library execute
+ * `git submodule add https://github.com/swiftmailer/swiftmailer.git libraries/swiftmailer`
+ * and uncomment the following lines.
+ */
+// use lithium\core\Libraries;
+// Libraries::add('swiftmailer', array(
+// 'prefix' => 'Swift_',
+// 'bootstrap' => 'lib/swift_required.php'
+// ));
+
+?>
@@ -0,0 +1,41 @@
+<?php
+
+namespace li3_mailer\net\mail;
+
+/**
+ * The `Delivery` class provides a consistent interface for configuring
+ * email delivery. Apart from the options for the adapter(s) the configuration
+ * can hold values for constructing the message (e.g. `'to'`, `'bcc'` and other
+ * supported options, see `Message`).
+ *
+ * A simple example configuration (**please note**: you'll need the
+ * SwiftMailer library for the `'Swift'` adapter to work):
+ *
+ * {{{Delivery::config(array(
+ * 'local' => array('adapter' => 'Simple', 'from' => 'you@example.com'),
+ * 'debug' => array('adapter' => 'Debug'),
+ * 'default' => array(
+ * 'adapter' => 'Swift',
+ * 'from' => 'you@example.com',
+ * 'bcc' => 'bcc@example.com',
+ * 'transport' => 'smtp',
+ * 'host' => 'example.com'
+ * )
+ * ));}}}
+ *
+ * @see li3_mailer\net\mail\Message
+ * @see li3_mailer\net\mail\transport\adapter\Simple
+ * @see li3_mailer\net\mail\transport\adapter\Debug
+ * @see li3_mailer\net\mail\transport\adapter\Swift
+ */
+class Delivery extends \lithium\core\Adaptable {
+ /**
+ * A dot-separated path for use by `Libraries::locate()`. Used to look up the correct type of
+ * adapters for this class.
+ *
+ * @var string
+ */
+ protected static $_adapters = 'adapter.net.mail.transport';
+}
+
+?>
Oops, something went wrong.

0 comments on commit ce088e8

Please sign in to comment.