Show:

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

<?php
/**
 * @module Users
 */
/**
 * Class representing 'Mobile' 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 mobile row in the Users database.
 *
 * @class Users_Mobile
 * @extends Base_Users_Mobile
 */
class Users_Mobile extends Base_Users_Mobile
{
	/**
	 * The setUp() method is called the first time
	 * an object of this class is constructed.
	 * @method setUp
	 */
	function setUp()
	{
		parent::setUp();
	}
	/**
	 * @method sendMessage
	 * @param {string} $view
	 *  The name of a view for the message. Fields are passed to this array.
	 * @param {array} $fields=array()
	 *  The fields referenced in the subject and/or view
	 * @param {array} $options=array()
	 *  Array of options. Can include:<br/>
	 *  "delay" => A delay, in milliseconds, to wait until sending email. Only works if Node server is listening.
	 * @param {string} [$options.language] Preferred language
	 * @return {boolean}
	 * @throws {Q_Exception_WrongType}
	 *	If phone number is invalid
	 */
	function sendMessage(
		$view,
		$fields = array(),
		$options = array())
	{
		if (!Q_Valid::phone($this->number, $number)) {
			throw new Q_Exception_WrongType(array(
				'field' => '$this->number',
				'type' => 'mobile number',
				'mobileNumber' => $this->number
			));
		}

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

		$app = Q::app();
		$body = Q::view($view, $fields, array('language' => $options['language']));
		
		/**
		 * @event Users/mobile/sendMessage {before}
		 * @param {string} view
		 * @param {array} fields
		 * @param {array} options
		 * @return {boolean}
		 */
		$result = Q::event('Users/mobile/sendMessage', compact('view', 'body', 'fields', 'options'), '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'],
				"mobileNumber" => $number,
				"body" => $body,
				"options" => $options
			));
		}
		
		if (!$sent) {
			$from = Q::ifset($options, 'from', Q_Config::get('Users', 'mobile', 'from', null));
			if (!isset($from)) {
				// deduce from base url
				$url_parts = parse_url(Q_Request::baseUrl());
				$domain = $url_parts['host'];
				$from = array("notifications@$domain", $domain);
			}

			$sid = Q_Config::get('Users', 'mobile', 'twilio', 'sid', null);
			$token = Q_Config::get('Users', 'mobile', 'twilio', 'token', null);

			if ($sid and $token) {
				$client = new Services_Twilio($sid, $token);
				/**
				 * @event Users/mobile/sendMessage/twilio {before}
				 * @param {string} view
				 * @param {array} fields
				 * @param {array} options
				 * @param {Services_Twilio} client You can call methods on this before sending sms
				 * @return {boolean}
				 */
				$result = Q::event('Users/mobile/sendMessage/twilio', compact('view', 'body', 'fields', 'options', 'client'), 'before');
				if (isset($result)) {
					return $result;
				}
				$message = $client->account->sms_messages->create(
					$from, // From a valid Twilio number
					$number, // Text this number
					$body
				);
			} else {
				if(!Q_Config::get('Users', 'email', 'smtp', null)){
					Q_Response::setNotice("Q/mobile", "Please set up transport in Users/mobile/twilio as in docs", false);
					if ($key = Q_Config::get('Users', 'mobile', 'log', 'key', 'mobile')) {
						$logMessage = "Would have sent message to $number:\n$body";
						Q::log($logMessage, $key);
					}
					return true;
				}

				$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("notifications@$domain", $domain);
				}

				// 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', 'mobile', 'log', 'key', 'mobile')) {
					$logMessage = "Sent message to $number:\n$body";
					if (!isset($transport)) {
						Q_Response::setNotice("Q/mobile", "Please set up Twilio in Users/mobile/twilio as in docs.", false);
						$logMessage = "Would have $logMessage";
					}
					Q::log($logMessage, $key);
				}

				if ($transport) {
					$email = new Zend_Mail();
					$email->setFrom(reset($from), next($from));
					$gateways = Q_Config::get('Users', 'mobile', 'gateways', array(
						'at&t' => 'txt.att.net',
						'sprint' => 'messaging.sprintpcs.com',
						'verizon' => 'vtext.com',
						't-mobile' => 'tmomail.net'
					));
					$number2 = substr($this->number, 2);
					foreach ($gateways as $k => $v) {
						$email->addTo($number2.'@'.$v);
					}
					$email->setBodyText($body);
					try {
						/**
						 * @event Users/mobile/sendMessage/gateway {before}
						 * @param {string} view
						 * @param {array} fields
						 * @param {array} options
						 * @param {Zend_Mail} email You can call methods on this before sending sms
						 * @return {boolean}
						 */
						$result = Q::event('Users/mobile/sendMessage/gateway', compact('view', 'body', 'fields', 'options', 'email'), 'before');
						if (isset($result)) {
							return $result;
						}
						$email->send($transport);
					} catch (Exception $e) {
						throw new Users_Exception_MobileMessage(array('error' => $e->getMessage()));
					}	
				}
			}
		}
		
		/**
		 * @event Users/mobile/sendMessage {after}
		 * @param {string} view
		 * @param {array} fields
		 * @param {array} options
		 * @param {string} mail
		 */
		Q::event(
			'Users/mobile/sendMessage', 
			compact('view', 'fields', 'options', 'mail', 'app', 'message', 'mail'),
			'after'
		);
		return true;
	}
	
	function resendActivationMessage(
		$view = null,
		$fields = array(),
		$options = array())
	{
		if (!isset($view)) {
			$view = Q_Config::get('Users', 'transactional', 'resend', 'sms', Q_Config::get(
				'Users', 'transactional', 'resend', 'sms', 'Users/sms/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' => 'mobile number'
				), 'mobileNumber');
			}
		}
		$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());
		$number = $this->number;
		if (substr($number, 0, 2) == '+1') {
			$number = substr($number, 2);
		}
		$link = Q_Uri::url('Users/activate?p=1&code='.urlencode($this->activationCode)
			. ' mobileNumber='.urlencode($number));
		$unsubscribe = Q_Uri::url('Users/unsubscribe?mobileNumber='.urlencode($number));
		$communityName = Users::communityName();
		$communitySuffix = Users::communitySuffix();
		/**
		 * @event Users/resend {before}
		 * @param {string} user
		 * @param {string} mobile
		 */
		Q::event('Users/resend', compact('user', 'mobile', 'link', 'unsubscribe'), 'before');
		$this->save();
		$fields2 = array_merge($fields, array(
			'user' => $user,
			'mobile' => $this,
			'app' => Q::app(),
			'communityName' => $communityName,
			'communitySuffix' => $communitySuffix,
			'baseUrl' => Q_Request::baseUrl(),
			'link' => $link,
			'unsubscribe' => $unsubscribe
		));
		$this->sendMessage( 
			$view, 
			$fields2,
			$options
		); // may throw exception if badly configured
		/**
		 * @event Users/resend {after}
		 * @param {string} user
		 * @param {string} mobile
		 */
		Q::event('Users/resend', compact('user', 'mobile', 'communityName'), '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_Mobile} Class instance
	 */
	static function __set_state(array $array) {
		$result = new Users_Mobile();
		foreach($array as $k => $v)
			$result->$k = $v;
		return $result;
	}
};