Email.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. <?php
  2. /*
  3. * FecShop file.
  4. *
  5. * @link http://www.fecshop.com/
  6. * @copyright Copyright (c) 2016 FecShop Software LLC
  7. * @license http://www.fecshop.com/license/
  8. */
  9. namespace fecshop\services;
  10. use Yii;
  11. /**
  12. * service mail :邮件服务部分
  13. * @author Terry Zhao <2358269014@qq.com>
  14. * @since 1.0
  15. */
  16. class Email extends Service
  17. {
  18. public $mailerConfig;
  19. public $defaultForm;
  20. public $mailerInfo;
  21. /**
  22. * 邮件模板部分动态数据提供类的返回数据的函数名字,使用默认值即可。
  23. */
  24. public $defaultObMethod = 'getLastData';
  25. protected $_mailer; // Array
  26. protected $_mailer_from; //Array
  27. protected $_from;
  28. /**
  29. * 在邮箱中显示的 邮箱地址
  30. */
  31. public function contactsEmailAddress()
  32. {
  33. $mailerInfo = $this->mailerInfo;
  34. if (isset($mailerInfo['contacts']['emailAddress'])) {
  35. return $mailerInfo['contacts']['emailAddress'];
  36. }
  37. }
  38. /**
  39. * 在邮箱中显示的 商城名字(Store Name).
  40. */
  41. public function storeName()
  42. {
  43. $mailerInfo = $this->mailerInfo;
  44. if (isset($mailerInfo['storeName'])) {
  45. return $mailerInfo['storeName'];
  46. }
  47. }
  48. /**
  49. * 在邮件中显示的 联系手机号
  50. * Yii::$service->email->customer->contactsPhone();.
  51. */
  52. public function contactsPhone()
  53. {
  54. $mailerInfo = $this->mailerInfo;
  55. if (isset($mailerInfo['phone'])) {
  56. return $mailerInfo['phone'];
  57. }
  58. }
  59. /**
  60. * @param $key | String
  61. * 得到MailConfig.
  62. */
  63. protected function getMailerConfig($key = 'default')
  64. {
  65. if (isset($this->mailerConfig[$key]) && $this->mailerConfig[$key]) {
  66. if (is_array($this->mailerConfig[$key])) {
  67. return $this->mailerConfig[$key];
  68. } elseif (is_string($this->mailerConfig[$key])) {
  69. return $this->getMailerConfig($this->mailerConfig[$key]);
  70. }
  71. }
  72. return '';
  73. }
  74. /**
  75. * 默认的默认form。邮件from.
  76. */
  77. protected function defaultForm($mailerConfig)
  78. {
  79. if (isset($mailerConfig['transport']['username'])) {
  80. if (!empty($mailerConfig['transport']['username'])) {
  81. return $mailerConfig['transport']['username'];
  82. }
  83. }
  84. return '';
  85. }
  86. /**
  87. * @param $mailerConfig | Array or String mailer组件的配置, 您可以设置为空,使用默认的邮箱配置,也可以设置为字符串,字符串对应配置中$mailerConfig对应的key。
  88. * 1.打开@fecshop/config/services/Config.php , 可以看到 $mailerConfig => ['default' => [...]]的配置,当该参数为空或'default'的时候,就使用该默认配置。
  89. * 2.当该参数设置除default之外的字符串的时候,就是 $mailerConfig 配置数组中其他的key对应的配置,如果不存在,则返回为空。
  90. * 3.您可以完全不使用配置数组中的配置,完全动态配置他,下面该参数动态配置的例子:
  91. * 注意:如果自定义传递邮箱配置,不同的配置,要使用不同的configKey
  92. * [
  93. * 'configKey' => [ # 唯一key,这个必须在 @fecshop/config/services/Config.php 中 $mailerConfig 配置数组中不存在该key值,否则将会重复。
  94. * 'class' => 'yii\swiftmailer\Mailer', # email组件对应的class
  95. * 'transport' => [ # 组件注入的配置参数。
  96. * 'class' => 'Swift_SmtpTransport',
  97. * 'host' => 'smtp.qq.net',
  98. * 'username' => 'support@mail.com',
  99. * 'password' => 'xxxx',
  100. * 'port' => '587',
  101. * 'encryption' => 'tls',
  102. * ],
  103. * 'messageConfig'=>[
  104. * 'charset'=>'UTF-8',
  105. * ],
  106. * ] //数组中只能一个configKey,配置多个无效,只有第一个有效。
  107. * ]
  108. * @return yii的mail组件compoent
  109. * 通过 $mailerConfigParam 的三种方式,可以使用系统配置的mail组件,也可以自己动态配置mail组件
  110. * 增强mail组件使用的方面和灵活。
  111. */
  112. protected function actionMailer($mailerConfigParam = '')
  113. {
  114. if (!$mailerConfigParam) {
  115. $key = 'default';
  116. } elseif (is_array($mailerConfigParam)) {
  117. $key_arr = array_keys($mailerConfigParam);
  118. $key = $key_arr[0];
  119. } elseif (is_string($mailerConfigParam)) {
  120. $key = $mailerConfigParam;
  121. } else {
  122. Yii::$service->helper->errors->add('you mail config param is not correct');
  123. return;
  124. }
  125. if (!$key) {
  126. Yii::$service->helper->errors->add('mail config key is empty');
  127. return;
  128. }
  129. if (!$this->_mailer[$key]) {
  130. $component_name = 'mailer_'.$key;
  131. if (!$mailerConfigParam) {
  132. $mailerConfig = $this->getMailerConfig();
  133. if (!is_array($mailerConfig) || empty($mailerConfig)) {
  134. Yii::$service->helper->errors->add('you must config mail var $mailerConfig is your mail config file');
  135. return;
  136. }
  137. Yii::$app->set($component_name, $mailerConfig);
  138. } elseif (is_array($mailerConfigParam)) {
  139. $mailerConfig = $mailerConfigParam[$key];
  140. if (!is_array($mailerConfig) || empty($mailerConfig)) {
  141. Yii::$service->helper->errors->add('function param $mailerConfigParam format is not correct');
  142. return;
  143. }
  144. $component_name .= 'custom_';
  145. Yii::$app->set($component_name, $mailerConfig);
  146. } elseif (is_string($mailerConfigParam)) {
  147. $mailerConfig = $this->getMailerConfig($mailerConfigParam);
  148. if (!is_array($mailerConfig) || empty($mailerConfig)) {
  149. Yii::$service->helper->errors->add('string param ($mailerConfigParam) can not find in config file , you must config var $mailerConfig in mail config file');
  150. return;
  151. }
  152. Yii::$app->set($component_name, $mailerConfig);
  153. }
  154. $this->_mailer_from[$key] = $this->defaultForm($mailerConfig);
  155. $this->_mailer[$key] = Yii::$app->get($component_name);
  156. }
  157. $this->_from = isset($this->_mailer_from[$key]) ? $this->_mailer_from[$key] : '';
  158. return isset($this->_mailer[$key]) ? $this->_mailer[$key] : '' ;
  159. }
  160. /**
  161. * @param $sendInfo | Array , example:
  162. * [
  163. * 'to' => $to,
  164. * 'subject' => $subject,
  165. * 'htmlBody' => $htmlBody,
  166. * 'senderName'=> $senderName,
  167. * ]
  168. * @param $mailerConfigParam | array or String,对于该参数的配置,
  169. * 您可以参看上面的函数 function actionMailer($mailerConfigParam = '') 或者到 @fecshop/config/services/Email.php参看 $mailerConfig的配置
  170. * 该函数用于发送邮件.
  171. */
  172. protected function actionSend($sendInfo, $mailerConfigParam = '')
  173. {
  174. $to = isset($sendInfo['to']) ? $sendInfo['to'] : '';
  175. $subject = isset($sendInfo['subject']) ? $sendInfo['subject'] : '';
  176. $htmlBody = isset($sendInfo['htmlBody']) ? $sendInfo['htmlBody'] : '';
  177. $senderName = isset($sendInfo['senderName']) ? $sendInfo['senderName'] : '';
  178. if (!$subject) {
  179. Yii::$service->helper->errors->add('email title is empty');
  180. return false;
  181. }
  182. if (!$htmlBody) {
  183. Yii::$service->helper->errors->add('email body is empty');
  184. return false;
  185. }
  186. $mailer = $this->mailer($mailerConfigParam);
  187. if (!$mailer) {
  188. Yii::$service->helper->errors->add('compose is empty, you must check you email config');
  189. return false;
  190. }
  191. if (!$this->_from) {
  192. Yii::$service->helper->errors->add('email send from is empty');
  193. return false;
  194. } else {
  195. $from = $this->_from;
  196. }
  197. if ($senderName) {
  198. $setFrom = [$from => $senderName];
  199. } else {
  200. $setFrom = $from;
  201. }
  202. try {
  203. $mailer->compose()
  204. ->setFrom($setFrom)
  205. ->setTo($to)
  206. ->setSubject($subject)
  207. ->setHtmlBody($htmlBody)
  208. ->send();
  209. return true;
  210. } catch (\Swift_TransportException $e) {
  211. $errorMessage = $e->getMessage();
  212. Yii::$service->helper->errors->add($errorMessage);
  213. return false;
  214. } catch (\Exception $e) {
  215. Yii::$service->helper->errors->add('send email fail');
  216. return false;
  217. }
  218. }
  219. /**
  220. * @param $widget | String,邮件模板中的动态数据的提供部分的class
  221. * @param $viewPath | String,邮件模板中的显示数据的html部分。
  222. * @param $langCode 当前的语言
  223. * @proeprty $params 传递给 $widget 对应的class,用于将数据传递过去。
  224. * 根据提供的动态数据提供者$widget 和 view路径$viewPath,语言$langCode,以及其他参数$params(这个数组会设置到$widget对应的class的params变量中)
  225. * 最终得到邮件标题和邮件内容
  226. * 如果当前语言的邮件模板不存在,则使用默认语言的模板。
  227. * 关于函数参数的例子值,可以参看配置文件 @fecshop/config/services/Email.php
  228. * 打开这个配置文件,可以看到 emailTheme部分的配置, 里面有 widget 和 viewPath的配置,
  229. * 配置和下面的参数是对应起来的,在执行下面的函数,会使用配置里面的参数,譬如:
  230. * @fecshop/services/email/Customer.php 中的函数 sendRegisterEmail($emailInfo) 里面对该函数的调用。
  231. */
  232. public function getSubjectAndBody($widget, $viewPath, $langCode = '', $params = [])
  233. {
  234. if (!$langCode) {
  235. $langCode = Yii::$service->store->currentLangCode;
  236. }
  237. if (!$langCode) {
  238. Yii::$service->helper->errors->add('langCode is empty');
  239. return;
  240. }
  241. $defaultLangCode = Yii::$service->fecshoplang->defaultLangCode;
  242. // 得到body部分的配置数组
  243. $bodyViewFile = $viewPath.'/body_'.$langCode.'.php';
  244. $bodyViewFilePath = Yii::getAlias($bodyViewFile);
  245. if (!file_exists($bodyViewFilePath)) { //如果当前语言的模板不存在,则使用默认语言的模板。
  246. $bodyViewFile = $viewPath.'/body_'.$defaultLangCode.'.php';
  247. $bodyViewFilePath = Yii::getAlias($bodyViewFile);
  248. }
  249. $bodyConfig = [
  250. 'class' => $widget,
  251. 'view' => $bodyViewFilePath,
  252. ];
  253. if (!empty($params)) {
  254. $bodyConfig['params'] = $params;
  255. }
  256. // 得到subject部分的配置数组
  257. $subjectViewFile = $viewPath.'/subject_'.$langCode.'.php';
  258. $subjectViewFilePath = Yii::getAlias($subjectViewFile);
  259. if (!file_exists($subjectViewFilePath)) {
  260. $subjectViewFile = $viewPath.'/subject_'.$defaultLangCode.'.php';
  261. $subjectViewFilePath = Yii::getAlias($subjectViewFile);
  262. }
  263. $subjectConfig = [
  264. 'class' => $widget,
  265. 'view' => $subjectViewFilePath,
  266. ];
  267. if (!empty($params)) {
  268. $subjectConfig['params'] = $params;
  269. }
  270. $emailSubject = $this->getHtmlContent($subjectConfig);
  271. $emailBody = $this->getHtmlContent($bodyConfig);
  272. return [$emailSubject, $emailBody];
  273. //$emailSubject = Yii::$service->page->widget->render($subjectConfigKey,$parentThis);
  274. //$emailBody = Yii::$service->page->widget->render($bodyConfigKey,$parentThis);
  275. }
  276. /**
  277. * @param $config | Array,example:
  278. * [
  279. * 'class' => $widget,
  280. * 'view' => $subjectViewFile,
  281. * 'params'=> $params
  282. * ];
  283. * @return String(text)
  284. * 通过配置得到邮件内容,原理是使用了 Yii::$app->view->renderFile()函数。
  285. */
  286. public function getHtmlContent($config)
  287. {
  288. if (isset($config['view']) && !empty($config['view'])) {
  289. $viewFile = $config['view'];
  290. unset($config['view']);
  291. $method = $this->defaultObMethod;
  292. $ob = Yii::createObject($config);
  293. $params = $ob->$method();
  294. return Yii::$app->view->renderFile($viewFile, $params);
  295. } else {
  296. //errors
  297. }
  298. }
  299. /**
  300. * @param $email_address | String 邮箱地址字符串
  301. * @return bool 如果格式正确,返回true
  302. */
  303. protected function actionValidateFormat($email_address)
  304. {
  305. if (preg_match("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$^", $email_address)) {
  306. return true;
  307. } else {
  308. return false;
  309. }
  310. }
  311. }