Show:

File: platform/plugins/Users/classes/Users/Email.php

<?php
/**
 * @module Users
 */
/**
 * Class representing 'Email' rows in the 'Users' database
 * You can create an object of this class either to
 * access its non-static methods, or to actually
 * represent a email row in the Users database.
 *
 * @class Users_Email
 * @extends Base_Users_Email
 */
class Users_Email extends Base_Users_Email
{
	/**
	 * The setUp() method is called the first time
	 * an object of this class is constructed.
	 * @method setUp
	 */
	function setUp()
	{
		parent::setUp();
	}
	/**
	 * Send e-mail message
	 * @method sendMessage
	 * @param {string|array} $subject
	 *  The subject. May contain variable references to members of the $fields array.
	 *  You can also pass an array($source, array($key1, ...)) to use Q_Text to obtain
	 *  the subject.
	 * @param {string} $view
	 *  The name of a view for the body. Fields are passed to it.
	 * @param {array} $fields=array()
	 *  The fields referenced in the subject and/or view
	 * @param {array} [$options=array()] Array of options. Can include:
	 * @param {array} [$options.html=false] Whether to send as HTML email.
	 * @param {array} [$options.name] A human-readable name in addition to the address to send to.
	 * @param {array} [$options.from] An array of (emailAddress, humanReadableName)
	 * @param {array} [$options.delay] A delay, in milliseconds, to wait until sending email. Only works if Node server is listening.
	 * @param {string} [$options.language] Preferred language
	 * @throws Q_Exception_WrongType
	 * @return {bool} True if success or throw exception
	 */
	function sendMessage(
		$subject, 
		$view,
		$fields = array(),
		$options = array())
	{
		if (!Q_Valid::email($this->address, $emailAddress)) {
			throw new Q_Exception_WrongType(array(
				'field' => '$this->address',
				'type' => 'email address',
				'emailAddress' => $this->address
			));
		}
		
		if (!isset($options['html'])) {
			$options['html'] = Q_Config::get('Q', 'views', $view, 'html', false);
		}

		// set language if didn't defined yet
		if (!isset($options['language'])) {
			$options['language'] = isset($this->userId) ? Users::getLanguage($this->userId) : null;
		}

		if (is_array($subject)) {
			$source = $subject[0];
			$keys = $subject[1];
			$texts = Q_Text::get($source, array('language' => $options['language']));
			$tree = new Q_Tree($texts);
			$keyPath = implode('/', $keys);
			$args = array_merge($keys, array("Missing $keyPath in $source"));
			$subject = call_user_func_array(array($tree, 'get'), $args);
		}
		
		$app = Q::app();
		$subject = Q_Handlebars::renderSource($subject, $fields);
		$body = Q::view($view, $fields, array('language' => $options['language']));

		$from = Q::ifset($options, 'from', Q_Config::get('Users', 'email', 'from', null));
		if (!isset($from)) {
			// deduce from base url
			$url_parts = parse_url(Q_Request::baseUrl());
			$domain = $url_parts['host'];
			$from = array("email@$domain", $domain);
		}
		if (!is_array($from)) {
			throw new Q_Exception_WrongType(array(
				'field' => '$options["from"]',
				'type' => 'array'
			));
		}
		
		/**
		 * @event Users/email/sendMessage {before}
		 * @param {string} subject
		 * @param {string} view
		 * @param {array} fields
		 * @param {array} options
		 * @return {boolean}
		 */
		$result = Q::event(
			'Users/email/sendMessage', 
			compact('view', 'fields', 'options', 'subject', 'body', 'from'), 
			'before'
		);
		if (isset($result)) {
			return $result;
		}
		
		$sent = false;
		if (!empty($options['delay'])) {
			// Try to use Node.js to send the message
			$sent = Q_Utils::sendToNode(array(
				"Q/method" => "Users/sendMessage",
				"delay" => $options['delay'],
				"emailAddress" => $emailAddress,
				"subject" => $subject,
				"body" => $body,
				"options" => $options
			));
		}
		
		if (!$sent) {
			// Set up the default mail transport
			$smtp = Q_Config::get('Users', 'email', 'smtp', array('host' => 'sendmail'));
			$host = Q::ifset($smtp, 'host', null);
			if ($host === 'sendmail') {
				$transport = new Zend_Mail_Transport_Sendmail('-f'.reset($from));
			} else {
				if (is_array($smtp)) {
					$host = $smtp['host'];
					unset($smtp['host']);
				} else if (is_string($smtp)) {
					$host = $smtp;
					$smtp = array();
				}
				if (isset($host)) {
					$transport = new Zend_Mail_Transport_Smtp($host, $smtp);
				} else {
					$transport = null;
				}
			}
			
			if ($key = Q_Config::get('Users', 'email', 'log', 'key', 'email')) {
				$logMessage = "Sent message to $emailAddress:\n$subject\n$body";
				if (!isset($transport)) {
					Q_Response::setNotice("Q/email", "Please set up SMTP in Users/email/smtp as in docs.", false);
					$logMessage = "Would have $logMessage";
				}
				Q::log($logMessage, $key);
			}

			if ($transport) {
				$email = new Zend_Mail();
				$email->setFrom(reset($from), next($from));
				if (isset($options['name'])) {
					$email->addTo($emailAddress, $options['name']);
				} else {
					$email->addTo($emailAddress);
				}
				$email->setSubject($subject);
				if (empty($options['html'])) {
					$email->setBodyText($body);
				} else {
					$email->setBodyHtml($body);
				}
				/**
				 * @event Users/email/sendMessage/email {before}
				 * @param {string} subject
				 * @param {string} view
				 * @param {array} fields
				 * @param {array} options
				 * @param {Zend_Mail} email You can use this object's methods to add bcc and more.
				 * @return {boolean}
				 */
				$result = Q::event(
					'Users/email/sendMessage/email', 
					compact('view', 'fields', 'options', 'subject', 'body', 'from', 'email'), 
					'before'
				);
				if (isset($result)) {
					return $result;
				}
				try {
					$email->send($transport);
				} catch (Exception $e) {
					throw new Users_Exception_EmailMessage(array('error' => $e->getMessage()));
				}
			}
		}
		
		/**
		 * @event Users/email/sendMessage {after}
		 * @param {string} subject
		 * @param {string} view
		 * @param {array} fields
		 * @param {array} options
		 * @param {string} mail
		 */
		Q::event(
			'Users/email/sendMessage', 
			compact('subject', 'view', 'fields', 'options', 'mail', 'app'),
			'after'
		);
		return true;
	}
	
	function resendActivationMessage(
		$subject = null,
		$view = null,
		$fields = array(),
		$options = array())
	{
		if (!isset($subject)) {
			$subject = Q_Config::get('Users', 'transactional', 'resend', 'subject', Q_Config::get(
				'Users', 'transactional', 'activation', 'subject', 
				'Did you forget your passphrase?'
			));
		}
		if (!isset($view)) {
			$view = Q_Config::get('Users', 'transactional', 'resend', 'body', Q_Config::get(
				'Users', 'transactional', 'activation', 'body', 'Users/email/activation.php'
			));
		}
		$user = $this->get('user', null);
		if (!$user) {
			$user = new Users_User();
			$user->id = $this->userId;
			if (!$user->retrieve()) {
				throw new Q_Exception_NotVerified(array(
					'type' => 'email address'
				), 'emailAddress');
			}
		}
		$minutes = Q_Config::get('Users', 'activation', 'expires', 60*24*7);
		$this->activationCode = strtolower(Q_Utils::unique(7));
		$this->activationCodeExpires = new Db_Expression(
			"CURRENT_TIMESTAMP + INTERVAL $minutes MINUTE"
		);
		$this->authCode = sha1(microtime() . mt_rand());
		$link = Q_Uri::url('Users/activate?p=1&code='.urlencode($this->activationCode)
			. ' emailAddress='.urlencode($this->address));
		$unsubscribe = Q_Uri::url('Users/unsubscribe?' . http_build_query(array(
			'authCode' =>  $this->authCode, 
			'emailAddress' => $this->address
		)));
		$communityName = Users::communityName();
		$communitySuffix = Users::communitySuffix();
		/**
		 * @event Users/resend {before}
		 * @param {string} user
		 * @param {string} email
		 */
		Q::event('Users/resend', compact('user', 'email', 'link', 'unsubscribe'), 'before');
		$this->save();
		$email = $this;
		$fields2 = array_merge($fields, array(
			'user' => $user,
			'email' => $this,
			'app' => Q::app(),
			'communityName' => $communityName,
			'communitySuffix' => $communitySuffix,
			'baseUrl' => Q_Request::baseUrl(),
			'link' => $link,
			'unsubscribe' => $unsubscribe
		));
		$this->sendMessage(
			$subject, 
			$view, 
			$fields2,
			$options
		); // may throw exception if badly configured
		/**
		 * @event Users/resend {after}
		 * @param {string} user
		 * @param {string} email
		 */
		Q::event('Users/resend', compact('user', 'email'), 'after');
	}

	/* * * */
	/**
	 * Implements the __set_state method, so it can work with
	 * with var_export and be re-imported successfully.
	 * @method __set_state
	 * @param {array} $array
	 * @return {Users_Email} Class instance
	 */
	static function __set_state(array $array) {
		$result = new Users_Email();
		foreach($array as $k => $v)
			$result->$k = $v;
		return $result;
	}
};