├── .gitignore ├── LICENSE ├── README.md ├── composer.json └── src ├── Contracts └── AccessTokenInterface.php ├── Credentials ├── DefaultCredential.php └── EasyWechatCredential.php ├── Exceptions ├── AccessTokenException.php ├── Exception.php └── SendTemplateMessageException.php ├── Wechat.php ├── WechatChannel.php ├── WechatMessage.php └── WechatServiceProvider.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.lock 3 | .idea -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 yansongda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

laravel-notification-wechat

2 | 3 |

4 | Latest Stable Version 5 | Latest Unstable Version 6 | License 7 |

8 | 9 | 不知道大家有没有基于 laravel 的消息通知开发过微信的模板消息通知,我反正是开发过多次了,以前开发总是写在 app 目录下,然后又一坨都写在自定义的 WechatChannel 里面,看这心里总是不舒服。多次之后,就有了这个…… 10 | 11 | ## 运行环境 12 | - PHP 5.6+ 13 | - composer 14 | 15 | ## 安装 16 | 1. composer 17 | `composer require yansongda/laravel-notification-wechat` 18 | 19 | 2. 注册 serviceprovider ( < laravel 5.5 ) 20 | `Yansongda\LaravelNotificationWechat\WechatServiceProvider::class` 21 | 22 | ## 使用 23 | ### 例子 24 | ```php 25 | 'Test First', 55 | 'keyword1' => 'keyword1', 56 | 'keyword2' => 'keyword2', 57 | 'keyword3' => ['keyword3', '#000000'], 58 | 'remark' => ['Test remark', '#fdfdfd'], 59 | ]; 60 | 61 | return WechatMessage::create($accessToken) 62 | ->to('oeTKvwYyc3PPAo3As3VRUBGppC0s') 63 | ->template("0qUpCTpgeYMFbjEKQ4W_D3ZNx5zUzQIfgasgqYX53mg") 64 | ->url('http://github.com/yansongda') 65 | ->data($data); 66 | } 67 | } 68 | ``` 69 | 70 | ### 支持的 WechatMessage 方法 71 | - `to(string $openid)`: 设置模板消息接收人的 openID 72 | - `template(string $templateID)`: 设置模板消息的模板 ID 73 | - `url(string $url)`: 设置点击模板消息后跳转 url,选填 74 | - `miniprogram(string $appid, string $pagepath)`: 设置点击模板消息后跳转的小程序,选填 75 | - `data(array $data)`: 设置模板消息数据 76 | 77 | ### 关于微信 AccessToken 78 | 微信发送模板消息时需要传递 accesstoken ,这里有三种方法去处理,方便与您现有的微信开发框架所集成。 79 | 80 | - 直接传递 accesstoken 值到 `WechatMessage::create($accesstoken)` 方法中,如上例所示; 81 | - 传递一个 `Yansongda\LaravelNotificatinoWechat\Contracts\AccessTokenInterface` 类到 `WechatMessage::create($CredentialClass)` 方法; 82 | - 直接在 config 文件夹中的 services.php 中添加 `'wechat' => ['appid' => 'xxx', 'appsecret' => 'xxx']`,系统将自动获取 accesstoken 并缓存,缓存的 key 为 `wechatAccessToken您的APPID` 您可以直接通过 laravel 的 Cache Facade 获取缓存的 accesstoken,当然,最保险的方案是通过 `(new Yansongda\LaravelNotificationWechat\Credential($appid, $appsecret))->getAccessToken()` 去获取 accesstoken。 83 | - 若使用EasyWechat(laravel包)且正常通信后,`WechatMessage::create()` 参数留空即可 84 | 85 | 具体可查看源码。 86 | 87 | ### 说明 88 | 1. 如果 `miniprogram` 与 `url` 同时存在,则优先使用小程序跳转,详情请参考[官方文档](https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277) 89 | 2. `data()`方法接收一个数组,其 `key` 为模板消息中的关键字,`value` 可以为字符串或数组。如果为字符串,则默认颜色为 `#173177`;如果为数组,则第一个参数为显示的数据,第二个参数为字体颜色 90 | 91 | ## 代码贡献 92 | **_欢迎 Fork 并提交 PR!_** 93 | 94 | ## LICENSE 95 | MIT 96 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yansongda/laravel-notification-wechat", 3 | "description": "Laravel Wechat Notifications Driver", 4 | "keywords": ["laravel", "wechat", "notification", "template"], 5 | "support": { 6 | "issues": "https://github.com/yansongda/laravel-notification-wechat/issues", 7 | "source": "https://github.com/yansongda/laravel-notification-wechat" 8 | }, 9 | "authors": [ 10 | { 11 | "name": "yansongda", 12 | "email": "me@yansongda.cn" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=7.0", 17 | "illuminate/notifications": "^5.5 || ^6.0", 18 | "illuminate/support": "^5.5 || ^6.0", 19 | "yansongda/supports": "^1.8 || ^2.0" 20 | }, 21 | "require-dev": { 22 | "phpunit/phpunit": "^6.2", 23 | "laravel/framework": "^5.5" 24 | }, 25 | "autoload": { 26 | "psr-4": { 27 | "Yansongda\\LaravelNotificationWechat\\": "src" 28 | } 29 | }, 30 | "autoload-dev": { 31 | "psr-4": { 32 | "Yansongda\\LaravelNotificationWechat\\Tests\\": "tests" 33 | } 34 | }, 35 | "extra": { 36 | "laravel": { 37 | "providers": [ 38 | "Yansongda\\LaravelNotificationWechat\\WechatServiceProvider" 39 | ] 40 | } 41 | }, 42 | "license": "MIT" 43 | } 44 | -------------------------------------------------------------------------------- /src/Contracts/AccessTokenInterface.php: -------------------------------------------------------------------------------- 1 | 11 | * 12 | * @return string 13 | */ 14 | public function getAccessToken(); 15 | } 16 | -------------------------------------------------------------------------------- /src/Credentials/DefaultCredential.php: -------------------------------------------------------------------------------- 1 | 46 | * 47 | * @param string|null $appid 48 | * @param string|null $appsecret 49 | */ 50 | public function __construct($appid = null, $appsecret = null) 51 | { 52 | $this->appid = $appid; 53 | $this->appsecret = $appsecret; 54 | } 55 | 56 | /** 57 | * Set wechat access_token. 58 | * 59 | * @author yansongda 60 | * 61 | * @param string $token 62 | * 63 | * @return DefaultCredential 64 | */ 65 | public function setAccessToken($token) 66 | { 67 | $this->accessToken = $token; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Get wechat access_token. 74 | * 75 | * @author yansongda 76 | * 77 | * @throws AccessTokenException 78 | * 79 | * @return string 80 | */ 81 | public function getAccessToken() 82 | { 83 | if (isset($this->accessToken)) { 84 | return $this->accessToken; 85 | } 86 | 87 | if (!is_null(Cache::get('wechatAccessToken'))) { 88 | return Cache::get('wechatAccessToken'); 89 | } 90 | 91 | if (is_null($this->appid) || is_null($this->appsecret)) { 92 | throw new AccessTokenException('Appid or appsecret is null', AccessTokenException::MISSING_APPID_APPSECRET); 93 | } 94 | 95 | $response = $this->requestForAccessToken(); 96 | 97 | Cache::put('wechatAccessToken'.$this->appid, $response['access_token'], $response['expires_in']); 98 | 99 | $this->accessToken = $response['access_token']; 100 | 101 | return $this->accessToken; 102 | } 103 | 104 | /** 105 | * requestForAccessToken. 106 | * 107 | * @author yansongda 108 | * 109 | * @throws AccessTokenException 110 | * 111 | * @return array 112 | */ 113 | protected function requestForAccessToken() 114 | { 115 | $data = $this->get('token', [ 116 | 'grant_type' => 'client_credential', 117 | 'appid' => $this->appid, 118 | 'secret' => $this->appsecret, 119 | ]); 120 | 121 | if (!isset($data['access_token'])) { 122 | throw new AccessTokenException('Error Get AccessToken:'.$data['errmsg'], $data['errcode'], $data); 123 | } 124 | 125 | return $data; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/Credentials/EasyWechatCredential.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | public function __construct() 22 | { 23 | } 24 | 25 | /** 26 | * Set wechat access_token. 27 | * 28 | * @author yansongda 29 | * 30 | * @param string $token 31 | * 32 | * @return EasyWechatCredential 33 | */ 34 | public function setAccessToken($token) 35 | { 36 | $this->accessToken = $token; 37 | 38 | return $this; 39 | } 40 | 41 | /** 42 | * Get wechat access_token. 43 | * 44 | * @author osi 45 | * 46 | * @return string 47 | */ 48 | public function getAccessToken() 49 | { 50 | if (!isset($this->accessToken)) { 51 | $app = app('wechat.official_account'); 52 | 53 | return $app->access_token->getToken()['access_token']; 54 | } 55 | 56 | return $this->accessToken; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Exceptions/AccessTokenException.php: -------------------------------------------------------------------------------- 1 | 26 | * 27 | * @param string $message 28 | * @param string|int $code 29 | * @param array|string $raw 30 | */ 31 | public function __construct($message, $code, $raw = []) 32 | { 33 | $this->raw = is_array($raw) ? $raw : []; 34 | 35 | parent::__construct($message, intval($code)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Exceptions/SendTemplateMessageException.php: -------------------------------------------------------------------------------- 1 | 20 | * 21 | * @param string $message 22 | * @param string|int $code 23 | * @param array $raw 24 | * @param AccessTokenInterface | null $credential 25 | */ 26 | public function __construct($message, $code = Exception::SEND_TEMPLATE_MESSAGE_ERROR, $raw = [], $credential = null) 27 | { 28 | parent::__construct($message, $code, $raw); 29 | 30 | $this->credential = $credential; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Wechat.php: -------------------------------------------------------------------------------- 1 | 31 | * 32 | * @param AccessTokenInterface $credential 33 | */ 34 | public function __construct(AccessTokenInterface $credential) 35 | { 36 | $this->credential = $credential; 37 | } 38 | 39 | /** 40 | * Send template message. 41 | * 42 | * @author yansongda 43 | * 44 | * @param string $params 45 | * 46 | * @throws SendTemplateMessageException 47 | * 48 | * @return array 49 | */ 50 | public function sendMessage($params) 51 | { 52 | $data = $this->post('message/template/send', $params, [ 53 | 'query' => [ 54 | 'access_token' => $this->credential->getAccessToken(), 55 | ], 56 | ]); 57 | 58 | if ($data['errcode'] != 0) { 59 | throw new SendTemplateMessageException($data['errmsg'], $data['errcode'], $data, $this->credential); 60 | } 61 | 62 | return $data; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/WechatChannel.php: -------------------------------------------------------------------------------- 1 | 23 | * 24 | * @param Wechat $wechat 25 | */ 26 | public function __construct(Wechat $wechat) 27 | { 28 | $this->wechat = $wechat; 29 | } 30 | 31 | /** 32 | * Send the given notification. 33 | * 34 | * @author yansongda 35 | * 36 | * @param mixed $notifiable 37 | * @param Notification $notification 38 | * 39 | * @throws Exceptions\SendTemplateMessageException 40 | * 41 | * @return array 42 | */ 43 | public function send($notifiable, Notification $notification) 44 | { 45 | if (!method_exists($notification, 'toWechat')) { 46 | throw new SendTemplateMessageException('Missing ToWechat Method In Wechat Channel', SendTemplateMessageException::MISSING_TOWECHAT_METHOD); 47 | } 48 | 49 | /* @var WechatMessage $message */ 50 | $message = $notification->toWechat($notifiable); 51 | 52 | if (is_string($message->credential)) { 53 | $credential = (new DefaultCredential())->setAccessToken($message->credential); 54 | 55 | $this->wechat = new Wechat($credential); 56 | } elseif ($message->credential instanceof AccessTokenInterface) { 57 | $this->wechat = new Wechat($message->credential); 58 | } 59 | 60 | $params = $message->toJson(); 61 | 62 | return $this->wechat->sendMessage($params); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/WechatMessage.php: -------------------------------------------------------------------------------- 1 | 27 | * 28 | * @param mixed $credential 29 | */ 30 | public function __construct($credential = null) 31 | { 32 | $this->credential = $credential; 33 | } 34 | 35 | /** 36 | * Create a new instance. 37 | * 38 | * @author yansongda 39 | * 40 | * @param mixed $credential 41 | * 42 | * @return WechatMessage 43 | */ 44 | public static function create($credential = null) 45 | { 46 | return new static($credential); 47 | } 48 | 49 | /** 50 | * Target user. 51 | * 52 | * @author yansongda 53 | * 54 | * @param string $openid 55 | * 56 | * @return WechatMessage 57 | */ 58 | public function to($openid) 59 | { 60 | $this->payload['touser'] = $openid; 61 | 62 | return $this; 63 | } 64 | 65 | /** 66 | * Target template id. 67 | * 68 | * @author yansongda 69 | * 70 | * @param string $template_id 71 | * 72 | * @return WechatMessage 73 | */ 74 | public function template($template_id) 75 | { 76 | $this->payload['template_id'] = $template_id; 77 | 78 | return $this; 79 | } 80 | 81 | /** 82 | * Template's target url. 83 | * 84 | * @author yansongda 85 | * 86 | * @param string $url 87 | * 88 | * @return WechatMessage 89 | */ 90 | public function url($url) 91 | { 92 | $this->payload['url'] = $url; 93 | 94 | return $this; 95 | } 96 | 97 | /** 98 | * Template's target miniprogram. 99 | * 100 | * @author yansongda 101 | * 102 | * @param string $appid 103 | * @param string $pagepath 104 | * 105 | * @return WechatMessage 106 | */ 107 | public function miniprogram($appid, $pagepath) 108 | { 109 | $this->payload['miniprogram']['appid'] = $appid; 110 | $this->payload['miniprogram']['pagepath'] = $pagepath; 111 | 112 | return $this; 113 | } 114 | 115 | /** 116 | * Target data. 117 | * 118 | * @author yansongda 119 | * 120 | * @param array $data 121 | * 122 | * @return WechatMessage 123 | */ 124 | public function data(array $data) 125 | { 126 | foreach ($data as $k => $v) { 127 | $this->payload['data'][$k] = is_array($v) ? 128 | ['value' => (new Collection($v))->first(), 'color' => (new Collection($v))->last()] : 129 | ['value' => $v, 'color' => '#173177']; 130 | } 131 | 132 | return $this; 133 | } 134 | 135 | /** 136 | * Convent payload to json format. 137 | * 138 | * @author yansongda 139 | * 140 | * @return string 141 | */ 142 | public function toJson() 143 | { 144 | return json_encode($this->payload); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/WechatServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->when(WechatChannel::class) 17 | ->needs(Wechat::class) 18 | ->give(function () { 19 | $credential = new DefaultCredential(config('services.wechat.appid'), config('services.wechat.appsecret')); 20 | 21 | if (class_exists('EasyWeChat\Factory')) { 22 | $credential = new EasyWechatCredential(); 23 | } 24 | 25 | return new Wechat($credential); 26 | }); 27 | } 28 | 29 | /** 30 | * Register any package services. 31 | */ 32 | public function register() 33 | { 34 | } 35 | } 36 | --------------------------------------------------------------------------------