From 91522a08cbe415cb2b032e0489c2da3e0b657f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Rodr=C3=ADguez?= Date: Thu, 29 Feb 2024 14:42:31 +0100 Subject: [PATCH 01/12] Add FCM HTTP V1 service --- composer.json | 3 +- readme.md | 57 ++++++++++ src/Channels/FcmV1Channel.php | 14 +++ src/Config/config.php | 10 ++ src/Config/fcmCertificates/.gitkeep | 0 src/FcmV1.php | 154 ++++++++++++++++++++++++++++ src/PushNotification.php | 3 +- 7 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 src/Channels/FcmV1Channel.php create mode 100644 src/Config/fcmCertificates/.gitkeep create mode 100644 src/FcmV1.php diff --git a/composer.json b/composer.json index 02511b4..4dd8cdd 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,8 @@ "php": "^7.1.3|^8.0", "guzzlehttp/guzzle": "^6.3 || ^7.0.1", "illuminate/support": "~5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0|^10.0", - "illuminate/notifications": "~5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0|^10.0" + "illuminate/notifications": "~5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0|^10.0", + "google/apiclient": "^2.15" }, "require-dev": { "phpunit/phpunit": "^7.5 || ^8.0 || ^9.0" diff --git a/readme.md b/readme.md index 49049e1..92cb7a9 100644 --- a/readme.md +++ b/readme.md @@ -11,6 +11,7 @@ This is an easy to use package to send push notification. * GCM * FCM +* FCMV1 * APN ## Installation @@ -59,6 +60,28 @@ $push->setConfig([ ]); ``` +The default configuration parameters for **FCMV1** are : + +* ```priority => 'normal'``` +* ```dry_run => false``` +* ```projectId => 'my-project-id'``` +* ```jsonFile => __DIR__ . '/fcmCertificates/file.json'``` + +You can dynamically update those values or adding new ones calling the method setConfig like so: +```php +$push->setConfig([ + 'priority' => 'high', + 'projectId' => 'my-real-project-id', + 'jsonFile' => 'path/to/credentials.json' +]); +``` + +To generate a credentials json file for your service account: + +* In the Firebase console, open **Settings** > [Service Accounts](https://console.firebase.google.com/project/_/settings/serviceaccounts/adminsdk). +* Click **Generate New Private Key**, then confirm by clicking **Generate Key**. +* Securely store the JSON file containing the key. + The default configuration parameters for **APN** are: @@ -117,6 +140,11 @@ For FCM Service: $push = new PushNotification('fcm'); ``` +For FCMV1 Service: +```php +$push = new PushNotification('fcmv1'); +``` + Now you may use any method that you need. Please see the API List. @@ -139,6 +167,11 @@ Now you may use any method that you need. Please see the API List. - [sendByTopic](https://github.com/edujugon/PushNotification#sendbytopic) +### Only for Fcmv1 + +- [setProjectId](https://github.com/edujugon/PushNotification#setprojectid) +- [setJsonFile](https://github.com/edujugon/PushNotification#setjsonfile) + > Go to [Usage samples](https://github.com/edujugon/PushNotification#usage-samples) directly. #### setService @@ -173,6 +206,30 @@ object setMessage(array $data) object setApiKey($api_key) ``` +#### setProjectId + +> Only for fcmv1 + +`setProjectId` method sets the Project ID of your App as a string. + +**Syntax** + +```php +object setProjectId($project_id) +``` + +#### setJsonFile + +> Only for fcmv1 + +`setJsonFile` method sets the path of credentials json file of your App. + +**Syntax** + +```php +object setJsonFile($api_key) +``` + #### setDevicesToken `setDevicesToken` method sets the devices' tokens, which you pass the token through parameter as array or string if it was only one. diff --git a/src/Channels/FcmV1Channel.php b/src/Channels/FcmV1Channel.php new file mode 100644 index 0000000..961b155 --- /dev/null +++ b/src/Channels/FcmV1Channel.php @@ -0,0 +1,14 @@ + [], ], + 'fcmv1' => [ + 'priority' => 'normal', + 'dry_run' => false, + 'projectId' => 'my-project-id', + 'jsonFile' => __DIR__ . '/fcmCertificates/file.json', + // Optional: Default Guzzle request options for each FCM request + // See https://docs.guzzlephp.org/en/stable/request-options.html + 'guzzle' => [], + ], 'apn' => [ 'certificate' => __DIR__ . '/iosCertificates/apns-dev-cert.pem', 'passPhrase' => 'secret', //Optional diff --git a/src/Config/fcmCertificates/.gitkeep b/src/Config/fcmCertificates/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/FcmV1.php b/src/FcmV1.php new file mode 100644 index 0000000..96dfae9 --- /dev/null +++ b/src/FcmV1.php @@ -0,0 +1,154 @@ +config = $this->initializeConfig('fcmv1'); + + $this->url = 'https://fcm.googleapis.com/v1/projects/' . $this->config['projectId'] . '/messages:send'; + + $this->client = new Client($this->config['guzzle'] ?? []); + } + + /** + * Set the apiKey for the notification + * @param string $apiKey + */ + public function setApiKey($apiKey) + { + throw new Exception('Not available on FCM V1'); + } + + /** + * Set the projectId for the notification + * @param string $projectId + */ + public function setProjectId($projectId) + { + $this->config['projectId'] = $projectId; + + $this->url = 'https://fcm.googleapis.com/v1/projects/' . $this->config['projectId'] . '/messages:send'; + } + + /** + * Set the jsonFile path for the notification + * @param string $jsonFile + */ + public function setJsonFile($jsonFile) + { + $this->config['jsonFile'] = $jsonFile; + } + + /** + * Set the needed headers for the push notification. + * + * @return array + */ + protected function addRequestHeaders() + { + return [ + 'Authorization' => 'Bearer ' . $this->getOauthToken(), + 'Content-Type' => 'application/json', + ]; + } + + /** + * Send Push Notification + * + * @param array $deviceTokens + * @param array $message + * + * @return \stdClass GCM Response + */ + public function send(array $deviceTokens, array $message) + { + // FCM v1 does not allows multiple devices at once + + $headers = $this->addRequestHeaders(); + $jsonData = ['message' => $this->buildMessage($message)]; + + $feedbacks = []; + + foreach ($deviceTokens as $deviceToken) { + try { + $jsonData['message']['token'] = $deviceToken; + + $result = $this->client->post( + $this->url, + [ + 'headers' => $headers, + 'json' => $jsonData, + ] + ); + + $json = $result->getBody(); + + $feedbacks[] = json_decode($json, false, 512, JSON_BIGINT_AS_STRING); + } catch (ClientException $e) { + $feedbacks[] = ['success' => false, 'error' => json_encode($e->getResponse())]; + } catch (\Exception $e) { + $feedbacks[] = ['success' => false, 'error' => $e->getMessage()]; + } + } + + $this->setFeedback($feedbacks); + } + + /** + * Prepare the data to be sent + * + * @param $topic + * @param $message + * @param $isCondition + * @return array + */ + protected function buildData($topic, $message, $isCondition) + { + $condition = $isCondition ? ['condition' => $topic] : ['to' => '/topics/' . $topic]; + + return [ + 'message' => array_merge($condition, $this->buildMessage($message)), + ]; + } + + protected function getOauthToken() + { + return Cache::remember( + Str::slug('fcm-v1-oauth-token-' . $this->config['projectId']), + Carbon::now()->addSeconds(self::CACHE_SECONDS), + function () { + $jsonFilePath = $this->config['jsonFile']; + + $googleClient = new GoogleClient(); + + $googleClient->setAuthConfig($jsonFilePath); + $googleClient->addScope(FirebaseCloudMessaging::FIREBASE_MESSAGING); + + $accessToken = $googleClient->fetchAccessTokenWithAssertion(); + + $oauthToken = $accessToken['access_token']; + + return $oauthToken; + } + ); + } +} diff --git a/src/PushNotification.php b/src/PushNotification.php index 6e7305f..6770f12 100644 --- a/src/PushNotification.php +++ b/src/PushNotification.php @@ -18,7 +18,8 @@ class PushNotification protected $servicesList = [ 'gcm' => Gcm::class, 'apn' => Apn::class, - 'fcm' => Fcm::class + 'fcm' => Fcm::class, + 'fcmv1' => FcmV1::class, ]; /** From e91253cba259e16b081ca8bd62eed8d33f252155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Rodr=C3=ADguez?= Date: Fri, 15 Mar 2024 12:21:33 +0100 Subject: [PATCH 02/12] Improve error management and unregistered devices tokens --- src/FcmV1.php | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/FcmV1.php b/src/FcmV1.php index 96dfae9..8f67cc3 100644 --- a/src/FcmV1.php +++ b/src/FcmV1.php @@ -16,6 +16,8 @@ class FcmV1 extends Fcm { const CACHE_SECONDS = 55 * 60; // 55 minutes + protected $unregisteredDeviceTokens = []; + /** * Fcm constructor. * Override parent constructor. @@ -87,6 +89,7 @@ public function send(array $deviceTokens, array $message) $jsonData = ['message' => $this->buildMessage($message)]; $feedbacks = []; + $this->unregisteredDeviceTokens = []; foreach ($deviceTokens as $deviceToken) { try { @@ -102,17 +105,41 @@ public function send(array $deviceTokens, array $message) $json = $result->getBody(); - $feedbacks[] = json_decode($json, false, 512, JSON_BIGINT_AS_STRING); + $feedbacks[$deviceToken] = [ + 'success' => true, + 'response' => json_decode($json, true, 512, JSON_BIGINT_AS_STRING), + ]; } catch (ClientException $e) { - $feedbacks[] = ['success' => false, 'error' => json_encode($e->getResponse())]; + $feedbacks[$deviceToken] = [ + 'success' => false, + 'error' => json_decode($e->getResponse()->getBody()->getContents(), true), + ]; + + $this->unregisteredDeviceTokens[] = $deviceToken; } catch (\Exception $e) { - $feedbacks[] = ['success' => false, 'error' => $e->getMessage()]; + $feedbacks[$deviceToken] = [ + 'success' => false, + 'error' => $e->getMessage(), + ]; + + $this->unregisteredDeviceTokens[] = $deviceToken; } } $this->setFeedback($feedbacks); } + /** + * Provide the unregistered tokens of the sent notification. + * + * @param array $devices_token + * @return array $tokenUnRegistered + */ + public function getUnregisteredDeviceTokens(array $devices_token) + { + return $this->unregisteredDeviceTokens; + } + /** * Prepare the data to be sent * From 7687053a6114775b9127893d9370326411c34ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Rodr=C3=ADguez?= Date: Wed, 20 Mar 2024 08:53:43 +0100 Subject: [PATCH 03/12] Fix dependencies --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 4dd8cdd..dcf8217 100644 --- a/composer.json +++ b/composer.json @@ -25,8 +25,8 @@ "require": { "php": "^7.1.3|^8.0", "guzzlehttp/guzzle": "^6.3 || ^7.0.1", - "illuminate/support": "~5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0|^10.0", - "illuminate/notifications": "~5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0|^10.0", + "illuminate/support": "~5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0", + "illuminate/notifications": "~5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0", "google/apiclient": "^2.15" }, "require-dev": { @@ -47,4 +47,4 @@ } } } -} +} \ No newline at end of file From 36b291c51fb7c7557f0fe59112dff393dbe26c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Rodr=C3=ADguez?= Date: Wed, 20 Mar 2024 11:03:19 +0100 Subject: [PATCH 04/12] Add concurrent request to FcmV1 --- src/Config/config.php | 1 + src/FcmV1.php | 74 +++++++++++++++++++++++++++---------------- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/src/Config/config.php b/src/Config/config.php index bc9f5b8..541d8f2 100644 --- a/src/Config/config.php +++ b/src/Config/config.php @@ -26,6 +26,7 @@ 'dry_run' => false, 'projectId' => 'my-project-id', 'jsonFile' => __DIR__ . '/fcmCertificates/file.json', + // 'concurrentRequests' => 5, // Optional, default 10 // Optional: Default Guzzle request options for each FCM request // See https://docs.guzzlephp.org/en/stable/request-options.html 'guzzle' => [], diff --git a/src/FcmV1.php b/src/FcmV1.php index 8f67cc3..20a8d4c 100644 --- a/src/FcmV1.php +++ b/src/FcmV1.php @@ -8,7 +8,10 @@ use Google\Client as GoogleClient; use Google\Service\FirebaseCloudMessaging; use GuzzleHttp\Client; -use GuzzleHttp\Exception\ClientException; +use GuzzleHttp\Exception\RequestException; +use GuzzleHttp\Pool; +use GuzzleHttp\Psr7\Request; +use GuzzleHttp\Psr7\Response as GuzzleResponse; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Str; @@ -16,8 +19,17 @@ class FcmV1 extends Fcm { const CACHE_SECONDS = 55 * 60; // 55 minutes + /** + * Number of concurrent requests to multiplex in the same connection. + * + * @var int + */ + protected $concurrentRequests = 10; + protected $unregisteredDeviceTokens = []; + protected $feedbacks = []; + /** * Fcm constructor. * Override parent constructor. @@ -29,6 +41,8 @@ public function __construct() $this->url = 'https://fcm.googleapis.com/v1/projects/' . $this->config['projectId'] . '/messages:send'; $this->client = new Client($this->config['guzzle'] ?? []); + + $this->concurrentRequests = $this->config['concurrentRequests'] ?? 10; } /** @@ -88,45 +102,51 @@ public function send(array $deviceTokens, array $message) $headers = $this->addRequestHeaders(); $jsonData = ['message' => $this->buildMessage($message)]; - $feedbacks = []; + $this->feedbacks = []; $this->unregisteredDeviceTokens = []; + $requests = []; foreach ($deviceTokens as $deviceToken) { - try { - $jsonData['message']['token'] = $deviceToken; + $jsonData['message']['token'] = $deviceToken; - $result = $this->client->post( - $this->url, - [ - 'headers' => $headers, - 'json' => $jsonData, - ] - ); + $body = json_encode($jsonData); + + $requests[$deviceToken] = new Request('POST', $this->url, $headers, $body); + } - $json = $result->getBody(); + $pool = new Pool($this->client, $requests, [ + 'concurrency' => $this->concurrentRequests, + 'fulfilled' => function (GuzzleResponse $response, $deviceToken) { + // this is delivered each successful response - $feedbacks[$deviceToken] = [ + $this->feedbacks[$deviceToken] = [ 'success' => true, - 'response' => json_decode($json, true, 512, JSON_BIGINT_AS_STRING), - ]; - } catch (ClientException $e) { - $feedbacks[$deviceToken] = [ - 'success' => false, - 'error' => json_decode($e->getResponse()->getBody()->getContents(), true), + 'response' => json_decode((string) $response->getBody(), true, 512, JSON_BIGINT_AS_STRING), ]; + }, + 'rejected' => function (RequestException $reason, $deviceToken) { + // this is delivered each failed request - $this->unregisteredDeviceTokens[] = $deviceToken; - } catch (\Exception $e) { - $feedbacks[$deviceToken] = [ + $error = json_decode((string) $reason->getResponse()->getBody(), true); + + $this->feedbacks[$deviceToken] = [ 'success' => false, - 'error' => $e->getMessage(), + 'error' => $error, ]; - $this->unregisteredDeviceTokens[] = $deviceToken; - } - } + if (isset($error['error']['status']) && $error['error']['status'] === 'INVALID_ARGUMENT') { + $this->unregisteredDeviceTokens[] = $deviceToken; + } + }, + ]); + + // Initiate the transfers and create a promise + $promise = $pool->promise(); + + // Force the pool of requests to complete. + $promise->wait(); - $this->setFeedback($feedbacks); + $this->setFeedback($this->feedbacks); } /** From ce21c0b21a39f306c5b72398bcea9e0e5e5b6795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Rodr=C3=ADguez?= Date: Fri, 22 Mar 2024 12:59:29 +0100 Subject: [PATCH 05/12] Fix class name --- src/Channels/FcmV1Channel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Channels/FcmV1Channel.php b/src/Channels/FcmV1Channel.php index 961b155..b131dc1 100644 --- a/src/Channels/FcmV1Channel.php +++ b/src/Channels/FcmV1Channel.php @@ -2,7 +2,7 @@ namespace Edujugon\PushNotification\Channels; -class FcmChannel extends GcmChannel +class FcmV1Channel extends GcmChannel { /** * {@inheritdoc} From 58fa9bb5b1d9623c057a729d21565a1fa2efebb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Rodr=C3=ADguez?= Date: Wed, 17 Apr 2024 19:57:19 +0200 Subject: [PATCH 06/12] Handle 404 FCM responses --- src/FcmV1.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FcmV1.php b/src/FcmV1.php index 20a8d4c..d677aed 100644 --- a/src/FcmV1.php +++ b/src/FcmV1.php @@ -134,7 +134,7 @@ public function send(array $deviceTokens, array $message) 'error' => $error, ]; - if (isset($error['error']['status']) && $error['error']['status'] === 'INVALID_ARGUMENT') { + if (isset($error['error']['code']) && in_array($error['error']['code'], [400, 404])) { $this->unregisteredDeviceTokens[] = $deviceToken; } }, From 7e2dcfcd9daf9ea9d717e67c47d48facd4febbec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Rodr=C3=ADguez?= Date: Thu, 20 Jun 2024 15:16:54 +0200 Subject: [PATCH 07/12] Auto update url after `setConfig()` --- src/FcmV1.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/FcmV1.php b/src/FcmV1.php index d677aed..8293fdc 100644 --- a/src/FcmV1.php +++ b/src/FcmV1.php @@ -74,6 +74,18 @@ public function setJsonFile($jsonFile) $this->config['jsonFile'] = $jsonFile; } + /** + * Update the values by key on config array from the passed array. If any key doesn't exist, it's added. + * @param array $config + */ + public function setConfig(array $config) + { + parent::setConfig($config); + + // Update url + $this->setProjectId($this->config['projectId']); + } + /** * Set the needed headers for the push notification. * From b6a55e7542eb6bbad74cb783abf573186c7f58a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Rodr=C3=ADguez?= Date: Thu, 20 Jun 2024 15:21:01 +0200 Subject: [PATCH 08/12] Laravel 11 support --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index dcf8217..3a47e20 100644 --- a/composer.json +++ b/composer.json @@ -23,10 +23,10 @@ } ], "require": { - "php": "^7.1.3|^8.0", + "php": "^7.1.3 || ^8.0", "guzzlehttp/guzzle": "^6.3 || ^7.0.1", - "illuminate/support": "~5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0", - "illuminate/notifications": "~5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0", + "illuminate/support": "~5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0", + "illuminate/notifications": "~5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0", "google/apiclient": "^2.15" }, "require-dev": { From 369f6eb2614cab3a5eabdba3ae0d811079b3ae1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Rodr=C3=ADguez?= Date: Mon, 23 Sep 2024 09:09:27 +0200 Subject: [PATCH 09/12] Fix Laravel notification payload generation --- src/Channels/FcmV1Channel.php | 57 +++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/Channels/FcmV1Channel.php b/src/Channels/FcmV1Channel.php index b131dc1..33c806f 100644 --- a/src/Channels/FcmV1Channel.php +++ b/src/Channels/FcmV1Channel.php @@ -2,6 +2,8 @@ namespace Edujugon\PushNotification\Channels; +use Edujugon\PushNotification\Messages\PushMessage; + class FcmV1Channel extends GcmChannel { /** @@ -11,4 +13,59 @@ protected function pushServiceName() { return 'fcmv1'; } + + /** + * {@inheritdoc} + */ + protected function buildData(PushMessage $message) + { + $data = []; + + if ($message->title != null || $message->body != null) { + $data = [ + 'notification' => [ + 'title' => $message->title, + 'body' => $message->body, + ], + ]; + } + + if ( + $message->icon || + $message->color || + $message->sound || + $message->click_action || + $message->badge + ) { + $data['android'] = [ + 'notification' => [] + ]; + + if (! empty($message->icon)) { + $data['android']['notification']['icon'] = $message->icon; + } + + if (! empty($message->color)) { + $data['android']['notification']['color'] = $message->color; + } + + if (! empty($message->sound)) { + $data['android']['notification']['sound'] = $message->sound; + } + + if (! empty($message->click_action)) { + $data['android']['notification']['click_action'] = $message->click_action; + } + + if (! empty($message->badge)) { + $data['android']['notification']['notification_count'] = $message->badge; + } + } + + if (! empty($message->extra)) { + $data['data'] = $message->extra; + } + + return $data; + } } From bd04ab90c3ebb6250817ba5af70afbfd34599c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Rodr=C3=ADguez?= Date: Mon, 23 Sep 2024 09:12:26 +0200 Subject: [PATCH 10/12] Handle 400 FCM responses --- src/FcmV1.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FcmV1.php b/src/FcmV1.php index 8293fdc..4b3afef 100644 --- a/src/FcmV1.php +++ b/src/FcmV1.php @@ -146,7 +146,7 @@ public function send(array $deviceTokens, array $message) 'error' => $error, ]; - if (isset($error['error']['code']) && in_array($error['error']['code'], [400, 404])) { + if (isset($error['error']['code']) && $error['error']['code'] === 404) { $this->unregisteredDeviceTokens[] = $deviceToken; } }, From 01da9cc256903fc22bf694cc6da7a9c779fdbd90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Rodr=C3=ADguez?= Date: Mon, 19 May 2025 17:52:37 +0200 Subject: [PATCH 11/12] Add cache store and duration to config. --- src/Config/config.php | 2 ++ src/FcmV1.php | 42 ++++++++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/Config/config.php b/src/Config/config.php index 541d8f2..60a6d43 100644 --- a/src/Config/config.php +++ b/src/Config/config.php @@ -26,6 +26,8 @@ 'dry_run' => false, 'projectId' => 'my-project-id', 'jsonFile' => __DIR__ . '/fcmCertificates/file.json', + // 'credentials_cache_seconds' => 55 * 60, // Optional. Credentials cache time in seconds. Maximum 60*60 seconds. + // 'cache_store' => null, // Optional. Cache store name. Null for default // 'concurrentRequests' => 5, // Optional, default 10 // Optional: Default Guzzle request options for each FCM request // See https://docs.guzzlephp.org/en/stable/request-options.html diff --git a/src/FcmV1.php b/src/FcmV1.php index 4b3afef..85ecfad 100644 --- a/src/FcmV1.php +++ b/src/FcmV1.php @@ -17,7 +17,7 @@ class FcmV1 extends Fcm { - const CACHE_SECONDS = 55 * 60; // 55 minutes + const DEFAULT_CREDENTIALS_CACHE_SECONDS = 55 * 60; // 55 minutes /** * Number of concurrent requests to multiplex in the same connection. @@ -26,6 +26,15 @@ class FcmV1 extends Fcm */ protected $concurrentRequests = 10; + /** + * Credentials cache time in seconds. Maximum 60*60 seconds. + * + * @var int + */ + protected $credentialsCacheSeconds = self::DEFAULT_CREDENTIALS_CACHE_SECONDS; + + protected $cacheStore = null; + protected $unregisteredDeviceTokens = []; protected $feedbacks = []; @@ -43,6 +52,10 @@ public function __construct() $this->client = new Client($this->config['guzzle'] ?? []); $this->concurrentRequests = $this->config['concurrentRequests'] ?? 10; + + $this->credentialsCacheSeconds = $this->config['credentials_cache_seconds'] ?? self::DEFAULT_CREDENTIALS_CACHE_SECONDS; + + $this->cacheStore = $this->config['cache_store'] ?? null; } /** @@ -191,23 +204,24 @@ protected function buildData($topic, $message, $isCondition) protected function getOauthToken() { - return Cache::remember( - Str::slug('fcm-v1-oauth-token-' . $this->config['projectId']), - Carbon::now()->addSeconds(self::CACHE_SECONDS), - function () { - $jsonFilePath = $this->config['jsonFile']; + return Cache::store($this->cacheStore) + ->remember( + Str::slug('fcm-v1-oauth-token-' . $this->config['projectId']), + Carbon::now()->addSeconds($this->credentialsCacheSeconds), + function () { + $jsonFilePath = $this->config['jsonFile']; - $googleClient = new GoogleClient(); + $googleClient = new GoogleClient(); - $googleClient->setAuthConfig($jsonFilePath); - $googleClient->addScope(FirebaseCloudMessaging::FIREBASE_MESSAGING); + $googleClient->setAuthConfig($jsonFilePath); + $googleClient->addScope(FirebaseCloudMessaging::FIREBASE_MESSAGING); - $accessToken = $googleClient->fetchAccessTokenWithAssertion(); + $accessToken = $googleClient->fetchAccessTokenWithAssertion(); - $oauthToken = $accessToken['access_token']; + $oauthToken = $accessToken['access_token']; - return $oauthToken; - } - ); + return $oauthToken; + } + ); } } From 0e9d756395b60a8f6b1832c86cc277304b690a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Rodr=C3=ADguez?= Date: Mon, 19 May 2025 17:53:23 +0200 Subject: [PATCH 12/12] Add base url constant. --- src/FcmV1.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/FcmV1.php b/src/FcmV1.php index 85ecfad..0ad62f8 100644 --- a/src/FcmV1.php +++ b/src/FcmV1.php @@ -17,6 +17,8 @@ class FcmV1 extends Fcm { + const BASE_URL = 'https://fcm.googleapis.com/v1/projects/'; + const DEFAULT_CREDENTIALS_CACHE_SECONDS = 55 * 60; // 55 minutes /** @@ -47,7 +49,7 @@ public function __construct() { $this->config = $this->initializeConfig('fcmv1'); - $this->url = 'https://fcm.googleapis.com/v1/projects/' . $this->config['projectId'] . '/messages:send'; + $this->url = self::BASE_URL . $this->config['projectId'] . '/messages:send'; $this->client = new Client($this->config['guzzle'] ?? []); @@ -75,7 +77,7 @@ public function setProjectId($projectId) { $this->config['projectId'] = $projectId; - $this->url = 'https://fcm.googleapis.com/v1/projects/' . $this->config['projectId'] . '/messages:send'; + $this->url = self::BASE_URL . $this->config['projectId'] . '/messages:send'; } /**