├── LICENSE.md ├── README.md ├── composer.json └── src ├── Exceptions ├── CouldNotSendNotification.php └── InvalidConfiguration.php ├── FirebaseChannel.php ├── FirebaseMessage.php └── FirebaseServiceProvider.php /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) Liliom 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # laravel-firebase 2 | This package makes it easy to send notifications using [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/) (FCM) with Laravel Notification Channel. 3 | 4 | ## Installation 5 | 6 | This package can be installed through Composer. 7 | 8 | ``` bash 9 | composer require liliom/laravel-firebase 10 | ``` 11 | 12 | If you don't use Laravel 5.5+ you have to add the service provider manually 13 | 14 | ```php 15 | // config/app.php 16 | 'providers' => [ 17 | ... 18 | Liliom\Firebase\FirebaseServiceProvider::class, 19 | ... 20 | ]; 21 | ``` 22 | 23 | Now add you Firebase API Key in `config/services.php`. 24 | 25 | ```php 26 | return [ 27 | .... 28 | 'firebase' => [ 29 | 'key' => '' 30 | ], 31 | .... 32 | ]; 33 | ``` 34 | 35 | ## Usage 36 | 37 | Les's create a notification using artisan commend: 38 | 39 | ```bash 40 | php artisan make:notification FirebaseNotification 41 | ``` 42 | 43 | Now you can use `firebase` channel in your `vie()` mothod. 44 | 45 | ```php 46 | public function via($notifiable) 47 | { 48 | return ['firebase']; 49 | } 50 | ``` 51 | 52 | Add a pubilc method `toFirebase($notifiable)` to your notification class, and return an instance of `FirebaseMessage`: 53 | 54 | ```php 55 | public function toFirebase($notifiable) 56 | { 57 | return (new \Liliom\Firebase\FirebaseMessage) 58 | ->notification([ 59 | 'title' => 'Notification title', 60 | 'body' => 'Notification body', 61 | 'sound' => '', // Optional 62 | 'icon' => '', // Optional 63 | 'click_action' => '' // Optional 64 | ]) 65 | ->setData([ 66 | 'param' => 'zxy' // Optional 67 | ]) 68 | ->setPriority('high'); // Default is 'normal' 69 | } 70 | ``` 71 | 72 | ## Available methods: 73 | 74 | - `setData`: To Set `data`. 75 | - `setPriority`: To Set `priority`. 76 | - `setTimeToLive`: To Set `time_to_live`. 77 | - `setCollapseKey`: To Set `collapse_key`. 78 | - `setNotification`: To Set `notification`. 79 | - `setCondition`: To Set `condition`. 80 | - `setContentAvailable`: To Set `content_available`. 81 | - `setMutableContent`: To Set `mutable_content`. 82 | - `setPackageName`: To Set `restricted_package_name`. 83 | 84 | When sending to specific device(s), make sure your notifiable entity has `routeNotificationForFirebase` method defined: 85 | > **Note:** You can send to many devices by return an array of tokens. 86 | 87 | ```php 88 | /** 89 | * Route notifications for Firebase channel. 90 | * 91 | * @return string|array 92 | */ 93 | public function routeNotificationForFirebase() 94 | { 95 | return $this->device_tokens; 96 | } 97 | ``` 98 | 99 | ## License 100 | 101 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 102 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "liliom/laravel-firebase", 3 | "description": "Laravel FCM (Firebase Cloud Messaging) Notification Channel", 4 | "keywords": [ 5 | "laravel", 6 | "fcm", 7 | "firebase", 8 | "notification", 9 | "channel", 10 | "notification-channel" 11 | ], 12 | "authors": [ 13 | { 14 | "name": "Hussam Abd", 15 | "email": "hussam3bd@liliom.co" 16 | } 17 | ], 18 | "license": "MIT", 19 | "require": { 20 | "php": ">=5.5.9", 21 | "illuminate/support": "5.*", 22 | "guzzlehttp/guzzle": "~6.0" 23 | }, 24 | "autoload": { 25 | "psr-4": { 26 | "Liliom\\Firebase\\": "src/" 27 | } 28 | }, 29 | "extra": { 30 | "laravel": { 31 | "providers": [ 32 | "Liliom\\Firebase\\FirebaseServiceProvider" 33 | ] 34 | } 35 | }, 36 | "minimum-stability": "stable" 37 | } 38 | -------------------------------------------------------------------------------- /src/Exceptions/CouldNotSendNotification.php: -------------------------------------------------------------------------------- 1 | client = $client; 28 | } 29 | 30 | /** 31 | * Send the given notification. 32 | * 33 | * @param mixed $notifiable 34 | * @param \Illuminate\Notifications\Notification $notification 35 | * 36 | * @throws \Liliom\Firebase\Exceptions\CouldNotSendNotification 37 | */ 38 | public function send($notifiable, Notification $notification) 39 | { 40 | $message = $notification->toFirebase($notifiable); 41 | 42 | if ($message->recipientNotGiven()) { 43 | if (!$to = $notifiable->routeNotificationFor('firebase')) { 44 | throw CouldNotSendNotification::missingRecipient(); 45 | } 46 | 47 | $message->to($to); 48 | } 49 | 50 | $this->client->post(self::API_URI, [ 51 | 'headers' => [ 52 | 'Authorization' => 'key=' . $this->getApiKey(), 53 | 'Content-Type' => 'application/json', 54 | ], 55 | 'body' => $message->payload(), 56 | ]); 57 | } 58 | 59 | /** 60 | * @return string 61 | */ 62 | private function getApiKey() 63 | { 64 | $key = config('services.firebase.key'); 65 | if (is_null($key)) { 66 | throw InvalidConfiguration::configurationNotSet(); 67 | } 68 | 69 | return $key; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/FirebaseMessage.php: -------------------------------------------------------------------------------- 1 | 'normal', 9 | 'HIGH' => 'high', 10 | ]; 11 | 12 | /** 13 | * @var array 14 | */ 15 | const OPTIONS_GETTERS = [ 16 | 'getData' => 'data', 17 | 'getPriority' => 'priority', 18 | 'getTimeToLive' => 'time_to_live', 19 | 'getCollapseKey' => 'collapse_key', 20 | 'getNotification' => 'notification', 21 | 'getCondition' => 'condition', 22 | 'getContentAvailable' => 'content_available', 23 | 'getMutableContent' => 'mutable_content', 24 | 'getPackageName' => 'restricted_package_name', 25 | ]; 26 | 27 | /** 28 | * @var mixed 29 | */ 30 | protected $recipient; 31 | 32 | /** 33 | * @var mixed 34 | */ 35 | protected $notification; 36 | 37 | /** 38 | * @var mixed 39 | */ 40 | protected $data; 41 | 42 | /** 43 | * @var string high|normal 44 | */ 45 | private $priority = self::PRIORITY['NORMAL']; 46 | 47 | /** 48 | * @var int 49 | */ 50 | private $timeToLive; 51 | 52 | /** 53 | * @var string 54 | */ 55 | private $condition; 56 | 57 | /** 58 | * @var string 59 | */ 60 | private $collapseKey; 61 | 62 | /** 63 | * @var boolean 64 | */ 65 | private $contentAvailable; 66 | 67 | /** 68 | * @var boolean 69 | */ 70 | private $mutableContent; 71 | 72 | /** 73 | * @var string 74 | */ 75 | private $packageName; 76 | 77 | /** 78 | * Recipient. 79 | * 80 | * @return $this 81 | */ 82 | public function to($recipient) 83 | { 84 | $this->recipient = $recipient; 85 | 86 | return $this; 87 | } 88 | 89 | /** 90 | * Get Recipient. 91 | * 92 | * @return mixed 93 | */ 94 | public function getRecipient() 95 | { 96 | return $this->recipient; 97 | } 98 | 99 | /** 100 | * Set timeToLive 101 | * 102 | * @param int $time 103 | * @return $this 104 | */ 105 | public function setTimeToLive($time) 106 | { 107 | $this->timeToLive = $time; 108 | 109 | return $this; 110 | } 111 | 112 | /** 113 | * Get timeToLive 114 | */ 115 | public function getTimeToLive() 116 | { 117 | return $this->timeToLive; 118 | } 119 | 120 | /** 121 | * Set restricted package name 122 | * 123 | * @param int $time 124 | * @return $this 125 | */ 126 | public function setPackageName($name) 127 | { 128 | $this->packageName = $name; 129 | 130 | return $this; 131 | } 132 | 133 | /** 134 | * Get packageName 135 | */ 136 | public function getPackageName() 137 | { 138 | return $this->packageName; 139 | } 140 | 141 | /** 142 | * The notification object to send to Firebase. `title` and `body` are required. 143 | * @param array $params ['title' => '', 'body' => '', 'sound' => '', 'icon' => '', 'click_action' => ''] 144 | * 145 | * @return $this 146 | */ 147 | public function notification(array $params) 148 | { 149 | $this->notification = $params; 150 | 151 | return $this; 152 | } 153 | 154 | /** 155 | * Get notification 156 | */ 157 | public function getNotification() 158 | { 159 | return $this->notification; 160 | } 161 | 162 | /** 163 | * @param string $condition 164 | * @return $this 165 | */ 166 | public function setCondition($condition) 167 | { 168 | $this->condition = $condition; 169 | 170 | return $this; 171 | } 172 | 173 | /** 174 | * @return string 175 | */ 176 | public function getCondition() 177 | { 178 | return $this->condition; 179 | } 180 | 181 | /** 182 | * @param string $collapseKey 183 | * @return $this 184 | */ 185 | public function setCollapseKey($collapseKey) 186 | { 187 | $this->collapseKey = $collapseKey; 188 | 189 | return $this; 190 | } 191 | 192 | /** 193 | * @return string 194 | */ 195 | public function getCollapseKey() 196 | { 197 | return $this->collapseKey; 198 | } 199 | 200 | /** 201 | * @param boolean $contentAvailable 202 | * @return $this 203 | */ 204 | public function setContentAvailable($contentAvailable) 205 | { 206 | $this->contentAvailable = $contentAvailable; 207 | 208 | return $this; 209 | } 210 | 211 | /** 212 | * @return boolean 213 | */ 214 | public function getContentAvailable() 215 | { 216 | return $this->contentAvailable; 217 | } 218 | 219 | /** 220 | * @param boolean $mutableContent 221 | * @return $this 222 | */ 223 | public function setMutableContent($mutableContent) 224 | { 225 | $this->mutableContent = $mutableContent; 226 | 227 | return $this; 228 | } 229 | 230 | /** 231 | * @return boolean 232 | */ 233 | public function getMutableContent() 234 | { 235 | return $this->mutableContent; 236 | } 237 | 238 | /** 239 | * @param array|null $data 240 | * @return $this 241 | */ 242 | public function setData($data = null) 243 | { 244 | $this->data = $data; 245 | 246 | return $this; 247 | } 248 | 249 | /** 250 | * @return $this 251 | */ 252 | public function getData() 253 | { 254 | return $this->data; 255 | } 256 | 257 | /** 258 | * @param high|normal $priority 259 | * 260 | * @return $this 261 | */ 262 | public function setPriority($priority) 263 | { 264 | if (isset(self::PRIORITY[strtoupper($priority)])) { 265 | $this->priority = self::PRIORITY[strtoupper($priority)]; 266 | } 267 | 268 | return $this; 269 | } 270 | 271 | /** 272 | * @return $this 273 | */ 274 | public function getPriority() 275 | { 276 | return $this->priority; 277 | } 278 | 279 | /** 280 | * @return string json 281 | */ 282 | public function payload() 283 | { 284 | $payload = []; 285 | 286 | if (is_array($this->getRecipient())) { 287 | $payload['registration_ids'] = $this->getRecipient(); 288 | } else { 289 | $payload['to'] = $this->getRecipient(); 290 | } 291 | 292 | foreach (self::OPTIONS_GETTERS as $function => $arrayKey) { 293 | if (method_exists($this, $function) && !empty($this->$function())) { 294 | $payload[$arrayKey] = $this->$function(); 295 | } 296 | } 297 | 298 | return \GuzzleHttp\json_encode($payload); 299 | } 300 | 301 | /** 302 | * Determine if recipient is not given. 303 | * 304 | * @return bool 305 | */ 306 | public function recipientNotGiven() 307 | { 308 | return !$this->recipient; 309 | } 310 | } 311 | -------------------------------------------------------------------------------- /src/FirebaseServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->make(ChannelManager::class)->extend('firebase', function() { 18 | return $this->app->make(FirebaseChannel::class); 19 | }); 20 | } 21 | } 22 | --------------------------------------------------------------------------------