示例#1
0
文件: Media.php 项目: niel/lithium
	/**
	 * Renders data (usually the result of a controller action) and generates a string
	 * representation of it, based on the type of expected output.
	 *
	 * @param object $response A reference to a Response object into which the operation will be
	 *        rendered. The content of the render operation will be assigned to the `$body`
	 *        property of the object, and the `'Content-type'` header will be set accordingly.
	 * @param mixed $data
	 * @param array $options
	 * @return void
	 * @filter
	 */
	public static function render(&$response, $data = null, array $options = array()) {
		$params = array('response' => &$response) + compact('data', 'options');
		$types = static::_types();
		$handlers = static::_handlers();

		static::_filter(__FUNCTION__, $params, function($self, $params) use ($types, $handlers) {
			$defaults = array('encode' => null, 'template' => null, 'layout' => '', 'view' => null);
			$response =& $params['response'];
			$data = $params['data'];
			$options = $params['options'] + array('type' => $response->type());

			$result = null;
			$type = $options['type'];

			if (!isset($handlers[$type])) {
				throw new MediaException("Unhandled media type `{$type}`.");
			}
			$handler = $options + $handlers[$type] + $defaults;
			$filter = function($v) { return $v !== null; };
			$handler = array_filter($handler, $filter) + $handlers['default'] + $defaults;

			if (isset($types[$type])) {
				$header = current((array) $types[$type]);
				$header .= $response->encoding ? "; charset={$response->encoding}" : '';
				$response->headers('Content-type', $header);
			}
			$response->body($self::invokeMethod('_handle', array($handler, $data, $response)));
		});
	}
示例#2
0
 /**
  * Translate the message, configuration and given options into
  * supported parameters for the Mailgun API.
  *
  * Returns an array including the following:
  *  - the API URL: can be configured two ways
  *    - with option keys `'api'` and `'domain'` the URL will be
  *      `$api/$domain/messages.mime`
  *      (`'api'` defaults to `'https://api.mailgun.net/v2'`)
  *    - with the option key `'url'` it will be final URL
  *  - the API key: can be configured with the option key `'key'`
  *  - parameters:
  *    - `'to'` address
  *    - generated message (with headers, in MIME format)
  *    - extra parameters, see `$_extraParameters`
  *    - variables with the option key `'variables'`
  *
  * @see li3_mailer\net\mail\transport\adapter\Mailgun::$_extraParameters
  * @see http://documentation.mailgun.net/api-sending.html
  * @param object $message The message to deliver.
  * @param array $options Given options.
  * @return array An array including the API URL, authentication credentials and parameters.
  */
 protected function _parameters($message, array $options = array())
 {
     $defaults = array('api' => 'https://api.mailgun.net/v2');
     $config = $this->_config + $options + $defaults;
     if (isset($config['url'])) {
         $url = $config['url'];
     } else {
         if (!isset($config['domain'])) {
             $error = "No `domain` (nor `url`) configured ";
             $error .= "for `Mailgun` transport adapter.";
             throw new RuntimeException($error);
         }
         if (substr($config['api'], -1) === '/') {
             $error = "API endpoint should not end with '/'.";
             throw new RuntimeException($error);
         }
         if (substr($config['domain'], 0, 1) === '/') {
             $error = "Domain should not start with '/'.";
             throw new RuntimeException($error);
         }
         if (substr($config['domain'], -1) === '/') {
             $error = "Domain should not end with '/'.";
             throw new RuntimeException($error);
         }
         $url = array($config['api'], $config['domain'], 'messages');
         $url = join($url, "/");
     }
     foreach (array('to', 'from', 'cc', 'bcc') as $field) {
         if (!$message->{$field}) {
             continue;
         }
         $parameters[$field] = $this->_address($message->{$field});
     }
     if ($subject = $message->subject) {
         $parameters += compact('subject');
     }
     if ($text = $message->body('text')) {
         $parameters += compact('text');
     }
     if ($html = $message->body('html')) {
         $parameters += compact('html');
     }
     foreach ($this->_extraParameters as $name => $type) {
         if (is_int($name)) {
             $name = $type;
             $type = null;
         }
         if (isset($config[$name])) {
             if ($type === "array") {
                 $list = array_values($config[$name]);
                 foreach ($list as $idx => $val) {
                     $key = 'o:' . $name . '[' . ($idx + 1) . ']';
                     $parameters[$key] = $val;
                 }
             } else {
                 $parameters['o:' . $name] = $config[$name];
             }
         }
     }
     if (isset($config['variables'])) {
         foreach ((array) $config['variables'] as $name => $val) {
             $parameters['v:' . $name] = $val;
         }
     }
     $auth = array('username' => 'api', 'password' => $config['key']);
     return array($url, $auth, $parameters);
 }
示例#3
0
 /**
  * Translate the message, configuration and given options into
  * supported parameters for the Mailgun API.
  *
  * Returns an array including the following:
  *  - the API URL: can be configured two ways
  *    - with option keys `'api'` and `'domain'` the URL will be
  *      `$api/$domain/messages.mime`
  *      (`'api'` defaults to `'https://api.mailgun.net/v2'`)
  *    - with the option key `'url'` it will be final URL
  *  - the API key: can be configured with the option key `'key'`
  *  - parameters:
  *    - `'to'` address
  *    - generated message (with headers, in MIME format)
  *    - extra parameters, see `$_extraParameters`
  *    - variables with the option key `'variables'`
  *
  * @see li3_mailer\net\mail\transport\adapter\Mailgun::$_extraParameters
  * @see http://documentation.mailgun.net/api-sending.html
  * @param object $message The message to deliver.
  * @param array $options Given options.
  * @return array An array including the API URL, authentication credentials and parameters.
  */
 protected function _parameters($message, array $options = array())
 {
     $defaults = array('api' => 'https://api.mailgun.net/v2');
     $config = $this->_config + $options + $defaults;
     if (isset($config['url'])) {
         $url = $config['url'];
     } else {
         if (!isset($config['domain'])) {
             $error = "No `domain` (nor `url`) configured ";
             $error .= "for `Mailgun` transport adapter.";
             throw new RuntimeException($error);
         }
         if (substr($config['api'], -1) === '/') {
             $error = "API endpoint should not end with '/'.";
             throw new RuntimeException($error);
         }
         if (substr($config['domain'], 0, 1) === '/') {
             $error = "Domain should not start with '/'.";
             throw new RuntimeException($error);
         }
         if (substr($config['domain'], -1) === '/') {
             $error = "Domain should not end with '/'.";
             throw new RuntimeException($error);
         }
         $url = array($config['api'], $config['domain'], 'messages');
         $url = join($url, "/");
     }
     foreach (array('to', 'from', 'cc', 'bcc') as $field) {
         if (!$message->{$field}) {
             continue;
         }
         $parameters[$field] = $this->_address($message->{$field});
     }
     if ($message->replyTo) {
         $parameters['h:Reply-To'] = $this->_address($message->replyTo);
     }
     if ($subject = $message->subject) {
         $parameters += compact('subject');
     }
     if ($text = $message->body('text')) {
         $parameters += compact('text');
     }
     if ($html = $message->body('html')) {
         $parameters += compact('html');
     }
     foreach ($message->attachments() as $key => $item) {
         if (isset($item['data'])) {
             if (is_resource($item['data'])) {
                 rewind($item['data']);
             }
             $file = tempnam(realpath(sys_get_temp_dir()) . '/', 'li3_mailer_attachment');
             $this->_temporaryFiles[] = $file;
             file_put_contents($file, $item['data']);
             $item['path'] = $file;
         }
         $parameters["attachment[{$key}]"] = new CURLFile($item['path'], $item['content-type'], $item['filename']);
     }
     foreach ($this->_extraParameters as $name => $type) {
         if (is_int($name)) {
             $name = $type;
             $type = null;
         }
         if (isset($config[$name])) {
             if ($type === "array") {
                 $list = array_values($config[$name]);
                 foreach ($list as $idx => $val) {
                     $key = 'o:' . $name . '[' . ($idx + 1) . ']';
                     $parameters[$key] = $val;
                 }
             } else {
                 $parameters['o:' . $name] = $config[$name];
             }
         }
     }
     if (isset($config['variables'])) {
         foreach ((array) $config['variables'] as $name => $val) {
             $parameters['v:' . $name] = $val;
         }
     }
     $auth = array('username' => 'api', 'password' => $config['key']);
     return array($url, $auth, $parameters);
 }
示例#4
0
 /**
  * Create a `Swift_Message` from `li3_mailer\net\mail\Message`.
  *
  * @see li3_mailer\net\mail\transport\adapter\Swift::$_messageProperties
  * @see li3_mailer\net\mail\transport\adapter\Swift::$_attachmentProperties
  * @see li3_mailer\net\mail\Message
  * @see Swift_Message
  * @param object $message The `Message` object to translate.
  * @return object The translated `Swift_Message` object.
  */
 protected function _message($message)
 {
     $swiftMessage = Swift_Message::newInstance();
     foreach ($this->_messageProperties as $prop => $translated) {
         if (is_int($prop)) {
             $prop = $translated;
         }
         if (!is_null($message->{$prop})) {
             $value = $message->{$prop};
             if ($translated === 'address') {
                 $translated = $prop;
                 if (is_array($value)) {
                     $newvalue = array();
                     foreach ($value as $name => $address) {
                         if (is_int($name)) {
                             $newvalue[] = $address;
                         } else {
                             $newvalue[$address] = $name;
                         }
                     }
                     $value = $newvalue;
                 }
             }
             $method = "set" . Inflector::camelize($translated);
             $swiftMessage->{$method}($value);
         }
     }
     $first = true;
     foreach ($message->types() as $type => $contentType) {
         if ($first) {
             $first = false;
             $swiftMessage->setBody($message->body($type), $contentType);
         } else {
             $swiftMessage->addPart($message->body($type), $contentType);
         }
     }
     $headers = $swiftMessage->getHeaders();
     foreach ($message->headers as $header => $value) {
         $headers->addTextHeader($header, $value);
     }
     foreach ($message->attachments() as $attachment) {
         if (isset($attachment['path'])) {
             $path = $attachment['path'];
             $swiftAttachment = Swift_Attachment::fromPath($path);
         } else {
             $data = $attachment['data'];
             $swiftAttachment = Swift_Attachment::newInstance($data);
         }
         foreach ($this->_attachmentProperties as $prop => $translated) {
             if (is_int($prop)) {
                 $prop = $translated;
             }
             if (isset($attachment[$prop])) {
                 $method = "set" . Inflector::camelize($translated);
                 $swiftAttachment->{$method}($attachment[$prop]);
             }
         }
         $swiftMessage->attach($swiftAttachment);
     }
     return $swiftMessage;
 }
示例#5
0
 /**
  * Generate headers and body of a message in MIME format.
  *
  * @param object $message The message.
  * @return array Message headers and body in MIME format.
  */
 protected function _generate($message)
 {
     $headers = $message->headers;
     foreach ($this->_messageAddresses as $property => $header) {
         if (is_int($property)) {
             $property = $header;
             $header = ucfirst($property);
         }
         $headers[$header] = $this->_address($message->{$property});
     }
     $headers['Date'] = date('r', $message->date);
     $headers['MIME-Version'] = "1.0";
     $types = $message->types();
     $attachments = $message->attachments();
     $charset = $message->charset;
     if (count($types) === 1 && count($attachments) === 0) {
         $type = key($types);
         $contentType = current($types);
         $headers['Content-Type'] = "{$contentType};charset=\"{$charset}\"";
         $body = wordwrap($message->body($type), 70);
     } else {
         $boundary = uniqid('LI3_MAILER_SIMPLE_');
         $contentType = "multipart/alternative;boundary=\"{$boundary}\"";
         $headers['Content-Type'] = $contentType;
         $body = "This is a multi-part message in MIME format.\n\n";
         foreach ($types as $type => $contentType) {
             $body .= "--{$boundary}\n";
             $contentType .= ";charset=\"{$charset}\"";
             $body .= "Content-Type: {$contentType}\n\n";
             $body .= wordwrap($message->body($type), 70) . "\n";
         }
         foreach ($attachments as $attachment) {
             if (isset($attachment['path'])) {
                 $local = $attachment['path'][0] === '/';
                 if ($local && !is_readable($attachment['path'])) {
                     $content = false;
                 } else {
                     $content = file_get_contents($attachment['path']);
                 }
                 if ($content === false) {
                     $error = "Can not attach path `{$attachment['path']}`.";
                     throw new RuntimeException($error);
                 }
             } else {
                 $content = $attachment['data'];
             }
             $body .= "--{$boundary}\n";
             if (isset($attachment['filename'])) {
                 $filename = $attachment['filename'];
             } else {
                 $filename = null;
             }
             if (isset($attachment['content-type'])) {
                 $contentType = $attachment['content-type'];
                 if ($filename && !preg_match('/;\\s+name=/', $contentType)) {
                     $contentType .= "; name=\"{$filename}\"";
                 }
                 $body .= "Content-Type: {$contentType}\n";
             }
             if (isset($attachment['disposition'])) {
                 $disposition = $attachment['disposition'];
                 $pattern = '/;\\s+filename=/';
                 if ($filename && !preg_match($pattern, $disposition)) {
                     $disposition .= "; filename=\"{$filename}\"";
                 }
                 $body .= "Content-Disposition: {$disposition}\n";
             }
             if (isset($attachment['id'])) {
                 $body .= "Content-ID: <{$attachment['id']}>\n";
             }
             $body .= "\n" . wordwrap($content, 70) . "\n";
         }
         $body .= "--{$boundary}--";
     }
     $headers = join("\r\n", array_map(function ($name, $value) {
         return "{$name}: {$value}";
     }, array_keys($headers), $headers));
     return array($headers, $body);
 }
示例#6
0
 /**
  * Handler for generating arguments list for POST methods.
  *
  * @see Lead\Resource\Controller::args()
  *
  * @param  object $request The request instance.
  * @param  array  $options An options array.
  * @return array
  */
 protected function _post($request, $options)
 {
     $payload = Payload::parse($request->body());
     if (!($collection = $payload->export())) {
         throw new ResourceException("No data provided for `{$this->name()}` resource(s), nothing to process.", 422);
     }
     $list = [];
     foreach ($collection as $data) {
         $list[] = [$options['binding']::create($data), $payload];
     }
     return $list;
 }
示例#7
0
 /**
  * Renders data (usually the result of a mailer delivery action) and generates a string
  * representation of it, based on the types of expected output. Also ensures the message's
  * fields are valid according to the RFC 2822.
  *
  * @param object $message A reference to a Message object into which the operation will be
  *        rendered. The content of the render operation will be assigned to the `$body`
  *        property of the object.
  * @param mixed $data
  * @param array $options
  * @return void
  * @filter
  */
 public static function render(&$message, $data = null, array $options = array())
 {
     $params = array('message' => &$message) + compact('data', 'options');
     $handlers = static::_handlers();
     static::_filter(__FUNCTION__, $params, function ($self, $params) use($handlers) {
         $defaults = array('template' => null, 'layout' => 'default', 'view' => null);
         $message =& $params['message'];
         $data = $params['data'];
         $options = $params['options'];
         foreach ((array) $message->types as $type) {
             if (!isset($handlers[$type])) {
                 throw new MediaException("Unhandled media type `{$type}`.");
             }
             $handler = $options + $handlers[$type] + $defaults + array('type' => $type);
             $filter = function ($v) {
                 return $v !== null;
             };
             $handler = array_filter($handler, $filter) + $handlers['default'] + $defaults;
             $handler['paths'] = $self::invokeMethod('_finalize_paths', array($handler['paths'], $options));
             $params = array($handler, $data, $message);
             $message->body($type, $self::invokeMethod('_handle', $params));
         }
         $message->ensureStandardCompliance();
     });
 }
示例#8
0
 /**
  * Helper method to get message property data for `String::insert()`
  * style formatters. Additional data may be added with the
  * configuration key `'message_data'`, which should be an array of:
  *
  * - strings: property names (with integer keys) or the special
  *   `'address'` value with the property name as the key (in which
  *   case the property will be transformed with `address()`).
  * - closures: the keys should be property names, the closure
  *   receives the message's property as the first argument and
  *   should return altered data. If the key is `''` the closure will
  *   receive the message object as the first argument and should
  *   return an array which will be merged into the data array.
  *
  * @see li3_mailer\net\mail\transport\adapter\Debug::_formatters()
  * @see li3_mailer\net\mail\transport\adapter\Debug::format()
  * @see li3_mailer\net\mail\Message
  * @param object $message Message.
  * @return array Message data.
  */
 protected function _message_data($message)
 {
     $config = $this->_config + array('message_data' => array());
     $map = (array) $config['message_data'] + array('subject', 'charset', 'return_path', 'sender' => 'address', 'from' => 'address', 'reply_to' => 'address', 'to' => 'address', 'cc' => 'address', 'bcc' => 'address', 'date' => function ($time) {
         return date('Y-m-d H:i:s', $time);
     }, 'types' => function ($types) {
         return join(', ', $types);
     }, 'headers' => function ($headers) {
         return join(PHP_EOL, $headers);
     }, 'body' => function ($bodies) {
         return join(PHP_EOL, array_map(function ($body) {
             return join(PHP_EOL, $body);
         }, $bodies));
     }, '' => function ($message) {
         return array_combine(array_map(function ($type) {
             return "body_{$type}";
         }, $message->types), array_map(function ($type) use($message) {
             return $message->body($type);
         }, $message->types));
     });
     $data = array();
     foreach ($map as $prop => $config) {
         if ($prop === '') {
             continue;
         }
         if (is_int($prop)) {
             $prop = $config;
             $config = null;
         }
         $value = $message->{$prop};
         if ($config instanceof Closure) {
             $value = $config($value);
         } else {
             if ($config == 'address') {
                 $value = $this->address($value);
             }
         }
         $data[$prop] = $value;
     }
     if (isset($map['']) && $map[''] instanceof Closure) {
         $data = $map['']($message) + $data;
     }
     return $data;
 }
示例#9
0
 /**
  * Renders data (usually the result of a controller action) and generates a string
  * representation of it, based on the type of expected output.
  *
  * @param object $response A reference to a Response object into which the operation will be
  *        rendered. The content of the render operation will be assigned to the `$body`
  *        property of the object, and the `'Content-type'` header will be set accordingly.
  * @param mixed $data
  * @param array $options
  * @return void
  * @filter
  * @todo Implement proper exception handling
  */
 public static function render(&$response, $data = null, $options = array())
 {
     $params = array('response' => &$response) + compact('data', 'options');
     $types = static::$_types;
     $handlers = static::$_handlers;
     static::_filter(__FUNCTION__, $params, function ($self, $params) use($types, $handlers) {
         $defaults = array('encode' => null, 'template' => null, 'layout' => null, 'view' => null);
         $response =& $params['response'];
         $data = $params['data'];
         $options = $params['options'] + array('type' => $response->type());
         $result = null;
         $type = $options['type'];
         $hasHandler = isset($handlers[$type]);
         $handler = $options + ($hasHandler ? $handlers[$type] : array()) + $defaults;
         if (!$handler['encode'] && !$handler['view'] && !$hasHandler) {
             throw new Exception("Unhandled media type '{$type}'");
         }
         $filter = function ($v) {
             return $v !== null;
         };
         $handler = array_filter($handler, $filter) + $handlers['default'] + $defaults;
         $response->body($self::invokeMethod('_handle', array($handler, $data, $options)));
         $response->headers('Content-type', current((array) $types[$type]));
     });
 }