Laravel version update

Laravel version update
This commit is contained in:
Manish Verma
2018-08-06 18:48:58 +05:30
parent d143048413
commit 126fbb0255
13678 changed files with 1031482 additions and 778530 deletions

View File

@@ -29,7 +29,7 @@ Or you can add it directly in your composer.json file:
{
"require": {
"brozot/laravel-fcm": "^1.2.0"
"brozot/laravel-fcm": "1.2.*"
}
}
@@ -124,8 +124,8 @@ use FCM;
#### Sending a Downstream Message to a Device
```php
$optionBuiler = new OptionsBuilder();
$optionBuiler->setTimeToLive(60*20);
$optionBuilder = new OptionsBuilder();
$optionBuilder->setTimeToLive(60*20);
$notificationBuilder = new PayloadNotificationBuilder('my title');
$notificationBuilder->setBody('Hello world')
@@ -134,7 +134,7 @@ $notificationBuilder->setBody('Hello world')
$dataBuilder = new PayloadDataBuilder();
$dataBuilder->addData(['a_data' => 'my_data']);
$option = $optionBuiler->build();
$option = $optionBuilder->build();
$notification = $notificationBuilder->build();
$data = $dataBuilder->build();
@@ -161,8 +161,8 @@ $downstreamResponse->tokensToRetry();
#### Sending a Downstream Message to Multiple Devices
```php
$optionBuiler = new OptionsBuilder();
$optionBuiler->setTimeToLive(60*20);
$optionBuilder = new OptionsBuilder();
$optionBuilder->setTimeToLive(60*20);
$notificationBuilder = new PayloadNotificationBuilder('my title');
$notificationBuilder->setBody('Hello world')
@@ -171,7 +171,7 @@ $notificationBuilder->setBody('Hello world')
$dataBuilder = new PayloadDataBuilder();
$dataBuilder->addData(['a_data' => 'my_data']);
$option = $optionBuiler->build();
$option = $optionBuilder->build();
$notification = $notificationBuilder->build();
$data = $dataBuilder->build();
@@ -203,6 +203,12 @@ A topics message is a notification message, data message, or both, that you send
> Note: Topic names must be managed by your app and known by your server. The Laravel-FCM package or fcm doesn't provide an easy way to do that.
The following use statement is required for the examples below:
```php
use LaravelFCM\Message\Topics;
```
#### Sending a Message to a Topic
```php
@@ -243,9 +249,9 @@ $topic->topic('news')->andTopic(function($condition) {
$condition->topic('economic')->orTopic('cultural');
})
});
$topicResponse = FCM::sendToTopic($topic, null, $notification, null)
$topicResponse = FCM::sendToTopic($topic, null, $notification, null);
$topicResponse->isSuccess();
$topicResponse->shouldRetry();

View File

@@ -12,7 +12,7 @@
],
"require": {
"php": ">=5.5.9",
"illuminate/support": ">=5.0.0",
"illuminate/support": "5.*",
"guzzlehttp/guzzle": "~6.0",
"monolog/monolog": "^1.19"
},

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,14 @@
<?php
return [
'driver' => env('FCM_PROTOCOL', 'http'),
'log_enabled' => true,
'driver' => env('FCM_PROTOCOL', 'http'),
'log_enabled' => false,
'http' => [
'server_key' => env('FCM_SERVER_KEY', 'Your FCM server key'),
'sender_id' => env('FCM_SENDER_ID', 'Your sender id'),
'server_send_url' => 'https://fcm.googleapis.com/fcm/send',
'server_group_url' => 'https://android.googleapis.com/gcm/notification',
'timeout' => 30.0, // in second
]
'http' => [
'server_key' => env('FCM_SERVER_KEY', 'Your FCM server key'),
'sender_id' => env('FCM_SENDER_ID', 'Your sender id'),
'server_send_url' => 'https://fcm.googleapis.com/fcm/send',
'server_group_url' => 'https://android.googleapis.com/gcm/notification',
'timeout' => 30.0, // in second
],
];

View File

@@ -1,20 +1,21 @@
<?php namespace LaravelFCM;
<?php
namespace LaravelFCM;
use GuzzleHttp\Client;
use Illuminate\Support\Manager;
class FCMManager extends Manager {
class FCMManager extends Manager
{
public function getDefaultDriver()
{
return $this->app[ 'config' ][ 'fcm.driver' ];
}
public function getDefaultDriver()
{
return $this->app[ 'config' ][ 'fcm.driver' ];
}
protected function createHttpDriver()
{
$config = $this->app[ 'config' ]->get('fcm.http', []);
protected function createHttpDriver()
{
$config = $this->app[ 'config' ]->get('fcm.http', []);
return new Client([ 'timeout' => $config[ 'timeout' ] ]);
}
}
return new Client(['timeout' => $config[ 'timeout' ]]);
}
}

View File

@@ -1,49 +1,53 @@
<?php namespace LaravelFCM;
<?php
namespace LaravelFCM;
use LaravelFCM\Sender\FCMGroup;
use LaravelFCM\Sender\FCMSender;
use Illuminate\Support\ServiceProvider;
class FCMServiceProvider extends ServiceProvider {
class FCMServiceProvider extends ServiceProvider
{
protected $defer = true;
protected $defer = true;
public function boot()
{
if (str_contains($this->app->version(), 'Lumen')) {
$this->app->configure('fcm');
} else {
$this->publishes([
__DIR__.'/../config/fcm.php' => config_path('fcm.php'),
]);
}
}
public function boot()
{
if (str_contains($this->app->version(), 'Lumen')) {
$this->app->configure('fcm');
}
else {
$this->publishes([
__DIR__."/../config/fcm.php" => config_path('fcm.php')
]);
}
}
public function register()
{
if (!str_contains($this->app->version(), 'Lumen')) {
$this->mergeConfigFrom(__DIR__.'/../config/fcm.php', 'fcm');
}
public function register()
{
$this->app->singleton('fcm.client', function($app) {
return (new FCMManager($app))->driver();
});
$this->app->singleton('fcm.client', function ($app) {
return (new FCMManager($app))->driver();
});
$this->app->bind('fcm.group', function($app) {
$client = $app[ 'fcm.client' ];
$url = $app[ 'config' ]->get('fcm.http.server_group_url');
$this->app->bind('fcm.group', function ($app) {
$client = $app[ 'fcm.client' ];
$url = $app[ 'config' ]->get('fcm.http.server_group_url');
return new FCMGroup($client, $url);
});
return new FCMGroup($client, $url);
});
$this->app->bind('fcm.sender', function($app) {
$client = $app[ 'fcm.client' ];
$url = $app[ 'config' ]->get('fcm.http.server_send_url');
$this->app->bind('fcm.sender', function ($app) {
$client = $app[ 'fcm.client' ];
$url = $app[ 'config' ]->get('fcm.http.server_send_url');
return new FCMSender($client, $url);
});
}
public function provides()
{
return [ 'fcm.client', 'fcm.group', 'fcm.sender' ];
}
return new FCMSender($client, $url);
});
}
public function provides()
{
return ['fcm.client', 'fcm.group', 'fcm.sender'];
}
}

View File

@@ -1,11 +1,13 @@
<?php namespace LaravelFCM\Facades;
<?php
namespace LaravelFCM\Facades;
use Illuminate\Support\Facades\Facade;
class FCM extends Facade {
protected static function getFacadeAccessor()
{
return 'fcm.sender';
}
}
class FCM extends Facade
{
protected static function getFacadeAccessor()
{
return 'fcm.sender';
}
}

View File

@@ -1,11 +1,13 @@
<?php namespace LaravelFCM\Facades;
<?php
namespace LaravelFCM\Facades;
use Illuminate\Support\Facades\Facade;
class FCMGroup extends Facade {
protected static function getFacadeAccessor()
{
return 'fcm.group';
}
}
class FCMGroup extends Facade
{
protected static function getFacadeAccessor()
{
return 'fcm.group';
}
}

View File

@@ -1,12 +1,12 @@
<?php namespace LaravelFCM\Message\Exceptions;
<?php
namespace LaravelFCM\Message\Exceptions;
use Exception;
/**
* Class InvalidOptionsException
*
* @package LaravelFCM\Response\Exceptions
* Class InvalidOptionsException.
*/
class InvalidOptionsException extends Exception {
}
class InvalidOptionsException extends Exception
{
}

View File

@@ -1,12 +1,12 @@
<?php namespace LaravelFCM\Message\Exceptions;
<?php
namespace LaravelFCM\Message\Exceptions;
use Exception;
/**
* Class NoTopicProvidedException
*
* @package LaravelFCM\Response\Exceptions
* Class NoTopicProvidedException.
*/
class NoTopicProvidedException extends Exception {
}
class NoTopicProvidedException extends Exception
{
}

View File

@@ -1,93 +1,110 @@
<?php namespace LaravelFCM\Message;
<?php
namespace LaravelFCM\Message;
use Illuminate\Contracts\Support\Arrayable;
/**
* Class Options
*
* @package LaravelFCM\Message
* Class Options.
*/
class Options implements Arrayable {
class Options implements Arrayable
{
/**
* @internal
*
* @var null|string
*/
protected $collapseKey;
/**
* @internal
* @var null|string
*/
protected $collapseKey;
/**
* @internal
*
* @var null|string
*/
protected $priority;
/**
* @internal
* @var null|string
*/
protected $priority;
/**
* @internal
*
* @var bool
*/
protected $contentAvailable;
/**
* @internal
* @var bool
*/
protected $contentAvailable;
/**
* @internal
*
* @var bool
*/
protected $isMutableContent = false;
/**
* @internal
* @var bool
*/
protected $delayWhileIdle;
/**
* @internal
*
* @var bool
*/
protected $delayWhileIdle;
/**
* @internal
* @var int|null
*/
protected $timeToLive;
/**
* @internal
*
* @var int|null
*/
protected $timeToLive;
/**
* @internal
* @var null|string
*/
protected $restrictedPackageName;
/**
* @internal
*
* @var null|string
*/
protected $restrictedPackageName;
/**
* @internal
* @var bool
*/
protected $isDryRun = false;
/**
* @internal
*
* @var bool
*/
protected $isDryRun = false;
/**
* Options constructor.
*
* @param OptionsBuilder $builder
*/
public function __construct(OptionsBuilder $builder)
{
$this->collapseKey = $builder->getCollapseKey();
$this->priority = $builder->getPriority();
$this->contentAvailable = $builder->isContentAvailable();
$this->delayWhileIdle = $builder->isDelayWhileIdle();
$this->timeToLive = $builder->getTimeToLive();
$this->restrictedPackageName = $builder->getRestrictedPackageName();
$this->isDryRun = $builder->isDryRun();
}
/**
* Options constructor.
*
* @param OptionsBuilder $builder
*/
public function __construct(OptionsBuilder $builder)
{
$this->collapseKey = $builder->getCollapseKey();
$this->priority = $builder->getPriority();
$this->contentAvailable = $builder->isContentAvailable();
$this->isMutableContent = $builder->isMutableContent();
$this->delayWhileIdle = $builder->isDelayWhileIdle();
$this->timeToLive = $builder->getTimeToLive();
$this->restrictedPackageName = $builder->getRestrictedPackageName();
$this->isDryRun = $builder->isDryRun();
}
/**
* Transform Option to array
*
* @return array
*/
function toArray()
{
$contentAvailable = $this->contentAvailable ? true : null;
$delayWhileIdle = $this->delayWhileIdle ? true : null;
$dryRun = $this->isDryRun ? true : null;
/**
* Transform Option to array.
*
* @return array
*/
public function toArray()
{
$contentAvailable = $this->contentAvailable ? true : null;
$mutableContent = $this->isMutableContent ? true : null;
$delayWhileIdle = $this->delayWhileIdle ? true : null;
$dryRun = $this->isDryRun ? true : null;
$options = [
'collapse_key' => $this->collapseKey,
'priority' => $this->priority,
'content_available' => $contentAvailable,
'delay_while_idle' => $delayWhileIdle,
'time_to_live' => $this->timeToLive,
'restricted_package_name' => $this->restrictedPackageName,
'dry_run' => $dryRun
];
$options = [
'collapse_key' => $this->collapseKey,
'priority' => $this->priority,
'content_available' => $contentAvailable,
'mutable_content' => $mutableContent,
'delay_while_idle' => $delayWhileIdle,
'time_to_live' => $this->timeToLive,
'restricted_package_name' => $this->restrictedPackageName,
'dry_run' => $dryRun,
];
return array_filter($options);
}
}
return array_filter($options);
}
}

View File

@@ -1,297 +1,331 @@
<?php namespace LaravelFCM\Message;
<?php
namespace LaravelFCM\Message;
use LaravelFCM\Message\Exceptions\InvalidOptionsException;
use ReflectionClass;
/**
* Builder for creation of options used by FCM
* Builder for creation of options used by FCM.
*
* Class OptionsBuilder
*
* @package LaravelFCM\Message\OptionsBuilder
*
* Form more information about options, please refer to google official documentation :
* @link http://firebase.google.com/docs/cloud-messaging/http-server-ref#downstream-http-messages-json
*/
class OptionsBuilder {
class OptionsBuilder
{
/**
* @internal
*
* @var string
*/
protected $collapseKey;
/**
* @internal
* @var string
*/
protected $collapseKey;
/**
* @internal
*
* @var string
*/
protected $priority;
/**
* @internal
* @var string
*
*/
protected $priority;
/**
* @internal
*
* @var bool
*/
protected $contentAvailable = false;
/**
* @internal
* @var boolean
*/
protected $contentAvailable = false;
/**
* @internal
* @var bool
*/
protected $mutableContent;
/**
* @internal
* @var boolean
*/
protected $delayWhileIdle = false;
/**
* @internal
*
* @var bool
*/
protected $delayWhileIdle = false;
/**
* @internal
* @var string
*/
protected $timeToLive;
/**
* @internal
*
* @var string
*/
protected $timeToLive;
/**
* @internal
* @var string
*/
protected $restrictedPackageName;
/**
* @internal
*
* @var string
*/
protected $restrictedPackageName;
/**
* @internal
* @var boolean
*/
protected $dryRun = false;
/**
* @internal
*
* @var bool
*/
protected $dryRun = false;
/**
* This parameter identifies a group of messages
* A maximum of 4 different collapse keys is allowed at any given time.
*
* @param String $collapseKey
*
* @return \LaravelFCM\Message\OptionsBuilder
*/
public function setCollapseKey($collapseKey)
{
$this->collapseKey = $collapseKey;
/**
* This parameter identifies a group of messages
* A maximum of 4 different collapse keys is allowed at any given time.
*
* @param string $collapseKey
*
* @return \LaravelFCM\Message\OptionsBuilder
*/
public function setCollapseKey($collapseKey)
{
$this->collapseKey = $collapseKey;
return $this;
}
return $this;
}
/**
* Sets the priority of the message. Valid values are "normal" and "high."
* By default, messages are sent with normal priority
*
* @param String $priority
*
* @return \LaravelFCM\Message\OptionsBuilder
*
* @throws InvalidOptionsException
*/
public function setPriority($priority)
{
if (!OptionsPriorities::isValid($priority)) {
throw new InvalidOptionsException('priority is not valid, please refer to the documentation or use the constants of the class "OptionsPriorities"');
}
$this->priority = $priority;
/**
* Sets the priority of the message. Valid values are "normal" and "high."
* By default, messages are sent with normal priority.
*
* @param string $priority
*
* @return \LaravelFCM\Message\OptionsBuilder
*
* @throws InvalidOptionsException
*/
public function setPriority($priority)
{
if (!OptionsPriorities::isValid($priority)) {
throw new InvalidOptionsException('priority is not valid, please refer to the documentation or use the constants of the class "OptionsPriorities"');
}
$this->priority = $priority;
return $this;
}
return $this;
}
/**
* support only Android and Ios
*
* An inactive client app is awoken.
* On iOS, use this field to represent content-available in the APNS payload.
* On Android, data messages wake the app by default.
* On Chrome, currently not supported.
*
* @param boolean $contentAvailable
*
* @return \LaravelFCM\Message\OptionsBuilder
*/
public function setContentAvailable($contentAvailable)
{
$this->contentAvailable = $contentAvailable;
/**
* support only Android and Ios.
*
* An inactive client app is awoken.
* On iOS, use this field to represent content-available in the APNS payload.
* On Android, data messages wake the app by default.
* On Chrome, currently not supported.
*
* @param bool $contentAvailable
*
* @return \LaravelFCM\Message\OptionsBuilder
*/
public function setContentAvailable($contentAvailable)
{
$this->contentAvailable = $contentAvailable;
return $this;
}
return $this;
}
/**
* When this parameter is set to true, it indicates that the message should not be sent until the device becomes active.
*
* @param boolean $delayWhileIdle
*
* @return \LaravelFCM\Message\OptionsBuilder
*/
public function setDelayWhileIdle($delayWhileIdle)
{
$this->delayWhileIdle = $delayWhileIdle;
/**
* support iOS 10+
*
* When a notification is sent and this is set to true,
* the content of the notification can be modified before it is displayed.
*
* @param String $isMutableContent
* @return OptionsBuilder
*/
public function setMutableContent($isMutableContent)
{
$this->mutableContent = $isMutableContent;
return $this;
}
return $this;
}
/**
* This parameter specifies how long the message should be kept in FCM storage if the device is offline
*
* @param int $timeToLive (in second) min:0 max:2419200
*
* @return \LaravelFCM\Message\OptionsBuilder
*
* @throws InvalidOptionException
*/
public function setTimeToLive($timeToLive)
{
if ($timeToLive < 0 || $timeToLive > 2419200) {
throw new InvalidOptionException("time to live must be between 0 and 2419200, current value is: {$timeToLive}");
}
$this->timeToLive = $timeToLive;
/**
* When this parameter is set to true, it indicates that the message should not be sent until the device becomes active.
*
* @param bool $delayWhileIdle
*
* @return \LaravelFCM\Message\OptionsBuilder
*/
public function setDelayWhileIdle($delayWhileIdle)
{
$this->delayWhileIdle = $delayWhileIdle;
return $this;
}
return $this;
}
/**
* This parameter specifies the package name of the application where the registration tokens must match in order to receive the message.
*
* @param string $restrictedPackageName
*
* @return \LaravelFCM\Message\OptionsBuilder
*/
public function setRestrictedPackageName($restrictedPackageName)
{
$this->restrictedPackageName = $restrictedPackageName;
/**
* This parameter specifies how long the message should be kept in FCM storage if the device is offline.
*
* @param int $timeToLive (in second) min:0 max:2419200
*
* @return \LaravelFCM\Message\OptionsBuilder
*
* @throws InvalidOptionException
*/
public function setTimeToLive($timeToLive)
{
if ($timeToLive < 0 || $timeToLive > 2419200) {
throw new InvalidOptionException("time to live must be between 0 and 2419200, current value is: {$timeToLive}");
}
$this->timeToLive = $timeToLive;
return $this;
}
return $this;
}
/**
* This parameter, when set to true, allows developers to test a request without actually sending a message.
* It should only be used for the development
*
* @param boolean $isDryRun
*
* @return \LaravelFCM\Message\OptionsBuilder
*/
public function setDryRun($isDryRun)
{
$this->dryRun = $isDryRun;
/**
* This parameter specifies the package name of the application where the registration tokens must match in order to receive the message.
*
* @param string $restrictedPackageName
*
* @return \LaravelFCM\Message\OptionsBuilder
*/
public function setRestrictedPackageName($restrictedPackageName)
{
$this->restrictedPackageName = $restrictedPackageName;
return $this;
}
return $this;
}
/**
* Get the collapseKey
*
* @return null|string
*/
public function getCollapseKey()
{
return $this->collapseKey;
}
/**
* This parameter, when set to true, allows developers to test a request without actually sending a message.
* It should only be used for the development.
*
* @param bool $isDryRun
*
* @return \LaravelFCM\Message\OptionsBuilder
*/
public function setDryRun($isDryRun)
{
$this->dryRun = $isDryRun;
/**
* Get the priority
*
* @return null|string
*/
public function getPriority()
{
return $this->priority;
}
return $this;
}
/**
* is content available
*
* @return boolean
*/
public function isContentAvailable()
{
return $this->contentAvailable;
}
/**
* Get the collapseKey.
*
* @return null|string
*/
public function getCollapseKey()
{
return $this->collapseKey;
}
/**
* is delay white idle
*
* @return boolean
*/
public function isDelayWhileIdle()
{
return $this->delayWhileIdle;
}
/**
* Get the priority.
*
* @return null|string
*/
public function getPriority()
{
return $this->priority;
}
/**
* get time to live
*
* @return null|int
*/
public function getTimeToLive()
{
return $this->timeToLive;
}
/**
* is content available.
*
* @return bool
*/
public function isContentAvailable()
{
return $this->contentAvailable;
}
/**
* get restricted package name
*
* @return null|string
*/
public function getRestrictedPackageName()
{
return $this->restrictedPackageName;
}
/**
* is mutable content
*
* @return bool
*/
public function isMutableContent()
{
return $this->mutableContent;
}
/**
* is dry run
*
* @return boolean
*/
public function isDryRun()
{
return $this->dryRun;
}
/**
* is delay white idle.
*
* @return bool
*/
public function isDelayWhileIdle()
{
return $this->delayWhileIdle;
}
/**
* build an instance of Options
*
* @return Options
*/
public function build()
{
return new Options($this);
}
/**
* get time to live.
*
* @return null|int
*/
public function getTimeToLive()
{
return $this->timeToLive;
}
/**
* get restricted package name.
*
* @return null|string
*/
public function getRestrictedPackageName()
{
return $this->restrictedPackageName;
}
/**
* is dry run.
*
* @return bool
*/
public function isDryRun()
{
return $this->dryRun;
}
/**
* build an instance of Options.
*
* @return Options
*/
public function build()
{
return new Options($this);
}
}
/**
* Class OptionsPriorities
*
* @package LaravelFCM\Message\OptionsPriorities
* Class OptionsPriorities.
*/
final class OptionsPriorities
{
/**
* @const high priority : iOS, these correspond to APNs priorities 10.
*/
const high = 'high';
/**
* @const high priority : iOS, these correspond to APNs priorities 10.
*/
const high = "high";
/**
* @const normal priority : iOS, these correspond to APNs priorities 5
*/
const normal = 'normal';
/**
* @const normal priority : iOS, these correspond to APNs priorities 5
*/
const normal = "normal";
/**
* @return array priorities available in fcm
*/
public static function getPriorities()
{
$class = new ReflectionClass(__CLASS__);
/**
* @return array priorities available in fcm
*/
static function getPriorities()
{
$class = new ReflectionClass(__CLASS__);
return $class->getConstants();
}
return $class->getConstants();
}
/**
* check if this priority is supported by fcm
*
* @param $priority
*
* @return bool
*/
static function isValid($priority)
{
return in_array($priority, static::getPriorities());
}
}
/**
* check if this priority is supported by fcm.
*
* @param $priority
*
* @return bool
*/
public static function isValid($priority)
{
return in_array($priority, static::getPriorities());
}
}

View File

@@ -1,38 +1,38 @@
<?php namespace LaravelFCM\Message;
<?php
namespace LaravelFCM\Message;
use Illuminate\Contracts\Support\Arrayable;
/**
* Class PayloadData
*
* @package LaravelFCM\Message
* Class PayloadData.
*/
class PayloadData implements Arrayable{
class PayloadData implements Arrayable
{
/**
* @internal
*
* @var array
*/
protected $data;
/**
* @internal
* @var array
*/
protected $data;
/**
* PayloadData constructor.
*
* @param PayloadDataBuilder $builder
*/
public function __construct(PayloadDataBuilder $builder)
{
$this->data = $builder->getData();
}
/**
* PayloadData constructor.
*
* @param PayloadDataBuilder $builder
*/
public function __construct(PayloadDataBuilder $builder)
{
$this->data = $builder->getData();
}
/**
* Transform payloadData to array
*
* @return array
*/
function toArray()
{
return $this->data;
}
}
/**
* Transform payloadData to array.
*
* @return array
*/
public function toArray()
{
return $this->data;
}
}

View File

@@ -1,77 +1,78 @@
<?php namespace LaravelFCM\Message;
<?php
namespace LaravelFCM\Message;
/**
* Class PayloadDataBuilder
* Class PayloadDataBuilder.
*
* Official google documentation :
* @link http://firebase.google.com/docs/cloud-messaging/http-server-ref#downstream-http-messages-json
*
* @package LaravelFCM\Message
* @link http://firebase.google.com/docs/cloud-messaging/http-server-ref#downstream-http-messages-json
*/
class PayloadDataBuilder {
class PayloadDataBuilder
{
/**
* @internal
*
* @var array
*/
protected $data;
/**
* @internal
* @var array
*/
protected $data;
/**
* add data to existing data.
*
* @param array $data
*
* @return PayloadDataBuilder
*/
public function addData(array $data)
{
$this->data = $this->data ?: [];
/**
* add data to existing data
*
* @param array $data
*
* @return PayloadDataBuilder
*/
public function addData(array $data)
{
$this->data = $this->data ?: [];
$this->data = array_merge($data, $this->data);
$this->data = array_merge($data, $this->data);
return $this;
}
return $this;
}
/**
* erase data with new data.
*
* @param array $data
*
* @return PayloadDataBuilder
*/
public function setData(array $data)
{
$this->data = $data;
/**
* erase data with new data
*
* @param array $data
*
* @return PayloadDataBuilder
*/
public function setData(array $data)
{
$this->data = $data;
return $this;
}
return $this;
}
/**
* Remove all data.
*/
public function removeAllData()
{
$this->data = null;
}
/**
* Remove all data
*/
public function removeAllData()
{
$this->data = null;
}
/**
* return data.
*
* @return array
*/
public function getData()
{
return $this->data;
}
/**
* return data
*
* @return array
*/
public function getData()
{
return $this->data;
}
/**
* generate a PayloadData
*
* @return PayloadData new PayloadData instance
*/
public function build()
{
return new PayloadData($this);
}
}
/**
* generate a PayloadData.
*
* @return PayloadData new PayloadData instance
*/
public function build()
{
return new PayloadData($this);
}
}

View File

@@ -1,134 +1,153 @@
<?php namespace LaravelFCM\Message;
<?php
namespace LaravelFCM\Message;
use Illuminate\Contracts\Support\Arrayable;
/**
* Class PayloadNotification
*
* @package LaravelFCM\Message
* Class PayloadNotification.
*/
class PayloadNotification implements Arrayable {
class PayloadNotification implements Arrayable
{
/**
* @internal
*
* @var null|string
*/
protected $title;
/**
* @internal
* @var null|String
*/
protected $title;
/**
* @internal
*
* @var null|string
*/
protected $body;
/**
* @internal
* @var null|String
*/
protected $body;
/**
* @internal
*
* @var null/string
*/
protected $channelId;
/**
* @internal
* @var null|String
*/
protected $icon;
/**
* @internal
*
* @var null|string
*/
protected $icon;
/**
* @internal
* @var null|String
*/
protected $sound;
/**
* @internal
*
* @var null|string
*/
protected $sound;
/**
* @internal
* @var null|String
*/
protected $badge;
/**
* @internal
*
* @var null|string
*/
protected $badge;
/**
* @internal
* @var null|String
*/
protected $tag;
/**
* @internal
*
* @var null|string
*/
protected $tag;
/**
* @internal
* @var null|String
*/
protected $color;
/**
* @internal
*
* @var null|string
*/
protected $color;
/**
* @internal
* @var null|String
*/
protected $clickAction;
/**
* @internal
*
* @var null|string
*/
protected $clickAction;
/**
* @internal
* @var null|String
*/
protected $bodyLocationKey;
/**
* @internal
*
* @var null|string
*/
protected $bodyLocationKey;
/**
* @internal
* @var null|String
*/
protected $bodyLocationArgs;
/**
* @internal
*
* @var null|string
*/
protected $bodyLocationArgs;
/**
* @internal
* @var null|String
*/
protected $titleLocationKey;
/**
* @internal
*
* @var null|string
*/
protected $titleLocationKey;
/**
* @internal
* @var null|String
*/
protected $titleLocationArgs;
/**
* @internal
*
* @var null|string
*/
protected $titleLocationArgs;
/**
* PayloadNotification constructor.
*
* @param PayloadNotificationBuilder $builder
*/
public function __construct(PayloadNotificationBuilder $builder)
{
$this->title = $builder->getTitle();
$this->body = $builder->getBody();
$this->icon = $builder->getIcon();
$this->sound = $builder->getSound();
$this->badge = $builder->getBadge();
$this->tag = $builder->getTag();
$this->color = $builder->getColor();
$this->clickAction = $builder->getClickAction();
$this->bodyLocationKey = $builder->getBodyLocationKey();
$this->bodyLocationArgs = $builder->getBodyLocationArgs();
$this->titleLocationKey = $builder->getTitleLocationKey();
$this->titleLocationArgs = $builder->getTitleLocationArgs();
/**
* PayloadNotification constructor.
*
* @param PayloadNotificationBuilder $builder
*/
public function __construct(PayloadNotificationBuilder $builder)
{
$this->title = $builder->getTitle();
$this->body = $builder->getBody();
$this->channelId = $builder->getChannelId();
$this->icon = $builder->getIcon();
$this->sound = $builder->getSound();
$this->badge = $builder->getBadge();
$this->tag = $builder->getTag();
$this->color = $builder->getColor();
$this->clickAction = $builder->getClickAction();
$this->bodyLocationKey = $builder->getBodyLocationKey();
$this->bodyLocationArgs = $builder->getBodyLocationArgs();
$this->titleLocationKey = $builder->getTitleLocationKey();
$this->titleLocationArgs = $builder->getTitleLocationArgs();
}
}
/**
* convert PayloadNotification to array.
*
* @return array
*/
public function toArray()
{
$notification = [
'title' => $this->title,
'body' => $this->body,
'android_channel_id' => $this->channelId,
'icon' => $this->icon,
'sound' => $this->sound,
'badge' => $this->badge,
'tag' => $this->tag,
'color' => $this->color,
'click_action' => $this->clickAction,
'body_loc_key' => $this->bodyLocationKey,
'body_loc_args' => $this->bodyLocationArgs,
'title_loc_key' => $this->titleLocationKey,
'title_loc_args' => $this->titleLocationArgs,
];
/**
* convert PayloadNotification to array
*
* @return array
*/
function toArray()
{
$notification = [
'title' => $this->title,
'body' => $this->body,
'icon' => $this->icon,
'sound' => $this->sound,
'badge' => $this->badge,
'tag' => $this->tag,
'color' => $this->color,
'click_action' => $this->clickAction,
'body_loc_key' => $this->bodyLocationKey,
'body_loc_args' => $this->bodyLocationArgs,
'title_loc_key' => $this->titleLocationKey,
'title_loc_args' => $this->titleLocationArgs,
];
// remove null values
$notification = array_filter($notification);
// remove null values
$notification = array_filter($notification);
return $notification;
}
}
return $notification;
}
}

View File

@@ -1,401 +1,447 @@
<?php namespace LaravelFCM\Message;
<?php
namespace LaravelFCM\Message;
/**
* Class PayloadNotificationBuilder
* Class PayloadNotificationBuilder.
*
* Official google documentation :
* @link http://firebase.google.com/docs/cloud-messaging/http-server-ref#downstream-http-messages-json
*
* @package LaravelFCM\Message
* @link http://firebase.google.com/docs/cloud-messaging/http-server-ref#downstream-http-messages-json
*/
class PayloadNotificationBuilder {
class PayloadNotificationBuilder
{
/**
* @internal
*
* @var null|string
*/
protected $title;
/**
* @internal
* @var null|String
*/
protected $title;
/**
* @internal
*
* @var null|string
*/
protected $body;
/**
* @internal
* @var null|String
*/
protected $body;
/**
* @internal
*
* @var null|string
*/
protected $icon;
/**
* @internal
* @var null|String
*/
protected $icon;
/**
* @internal
*
* @var null|string
*/
protected $sound;
/**
* @internal
* @var null|String
*/
protected $sound;
/**
* @internal
*
* @var null|string
*/
protected $channelId;
/**
* @internal
* @var null|String
*/
protected $badge;
/**
* @internal
*
* @var null|string
*/
protected $badge;
/**
* @internal
* @var null|String
*/
protected $tag;
/**
* @internal
*
* @var null|string
*/
protected $tag;
/**
* @internal
* @var null|String
*/
protected $color;
/**
* @internal
*
* @var null|string
*/
protected $color;
/**
* @internal
* @var null|String
*/
protected $clickAction;
/**
* @internal
*
* @var null|string
*/
protected $clickAction;
/**
* @internal
* @var null|String
*/
protected $bodyLocationKey;
/**
* @internal
*
* @var null|string
*/
protected $bodyLocationKey;
/**
* @internal
* @var null|String
*/
protected $bodyLocationArgs;
/**
* @internal
*
* @var null|string
*/
protected $bodyLocationArgs;
/**
* @internal
* @var null|String
*/
protected $titleLocationKey;
/**
* @internal
*
* @var null|string
*/
protected $titleLocationKey;
/**
* @internal
* @var null|String
*/
protected $titleLocationArgs;
/**
* @internal
*
* @var null|string
*/
protected $titleLocationArgs;
/**
* Title must be present on android notification and ios (watch) notification
*
* @param String $title
*/
public function __construct($title = null)
{
$this->title = $title;
}
/**
* Title must be present on android notification and ios (watch) notification.
*
* @param string $title
*/
public function __construct($title = null)
{
$this->title = $title;
}
/**
* Indicates notification title. This field is not visible on iOS phones and tablets.
* but it is required for android
*
* @param String $title
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setTitle($title) {
$this->title = $title;
/**
* Indicates notification title. This field is not visible on iOS phones and tablets.
* but it is required for android.
*
* @param string $title
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
return $this;
}
/**
* Indicates notification body text.
*
* @param String $body
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setBody($body)
{
$this->body = $body;
/**
* Indicates notification body text.
*
* @param string $body
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setBody($body)
{
$this->body = $body;
return $this;
}
return $this;
}
/**
* Supported Android
* Indicates notification icon. example : Sets value to myicon for drawable resource myicon.
*
* @param String $icon
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setIcon($icon)
{
$this->icon = $icon;
/**
* Set a channel ID for android API >= 26.
*
* @param string $channelId
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setChannelId($channelId)
{
$this->channelId = $channelId;
return $this;
}
return $this;
}
/**
* Indicates a sound to play when the device receives a notification.
* Supports default or the filename of a sound resource bundled in the app.
*
* @param String $sound
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setSound($sound)
{
$this->sound = $sound;
/**
* Supported Android
* Indicates notification icon. example : Sets value to myicon for drawable resource myicon.
*
* @param string $icon
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setIcon($icon)
{
$this->icon = $icon;
return $this;
}
return $this;
}
/**
* Supported Ios
*
* Indicates the badge on the client app home icon.
*
* @param String $badge
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setBadge($badge)
{
$this->badge = $badge;
/**
* Indicates a sound to play when the device receives a notification.
* Supports default or the filename of a sound resource bundled in the app.
*
* @param string $sound
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setSound($sound)
{
$this->sound = $sound;
return $this;
}
return $this;
}
/**
* Supported Android
*
* Indicates whether each notification results in a new entry in the notification drawer on Android.
* If not set, each request creates a new notification.
* If set, and a notification with the same tag is already being shown, the new notification replaces the existing one in the notification drawer.
*
* @param String $tag
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setTag($tag)
{
$this->tag = $tag;
/**
* Supported Ios.
*
* Indicates the badge on the client app home icon.
*
* @param string $badge
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setBadge($badge)
{
$this->badge = $badge;
return $this;
}
return $this;
}
/**
* Supported Android
*
* Indicates color of the icon, expressed in #rrggbb format
*
* @param String $color
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setColor($color) {
$this->color = $color;
/**
* Supported Android.
*
* Indicates whether each notification results in a new entry in the notification drawer on Android.
* If not set, each request creates a new notification.
* If set, and a notification with the same tag is already being shown, the new notification replaces the existing one in the notification drawer.
*
* @param string $tag
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setTag($tag)
{
$this->tag = $tag;
return $this;
}
return $this;
}
/**
* Indicates the action associated with a user click on the notification
*
* @param String $action
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setClickAction($action)
{
$this->clickAction = $action;
/**
* Supported Android.
*
* Indicates color of the icon, expressed in #rrggbb format
*
* @param string $color
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setColor($color)
{
$this->color = $color;
return $this;
}
return $this;
}
/**
* Indicates the key to the title string for localization.
*
* @param String $titleKey
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setTitleLocationKey($titleKey)
{
$this->titleLocationKey = $titleKey;
/**
* Indicates the action associated with a user click on the notification.
*
* @param string $action
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setClickAction($action)
{
$this->clickAction = $action;
return $this;
}
return $this;
}
/**
* Indicates the string value to replace format specifiers in the title string for localization.
*
* @param mixed $titleArgs
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setTitleLocationArgs($titleArgs)
{
$this->titleLocationArgs = $titleArgs;
/**
* Indicates the key to the title string for localization.
*
* @param string $titleKey
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setTitleLocationKey($titleKey)
{
$this->titleLocationKey = $titleKey;
return $this;
}
return $this;
}
/**
* Indicates the key to the body string for localization.
*
* @param String $bodyKey
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setBodyLocationKey($bodyKey)
{
$this->bodyLocationKey = $bodyKey;
/**
* Indicates the string value to replace format specifiers in the title string for localization.
*
* @param mixed $titleArgs
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setTitleLocationArgs($titleArgs)
{
$this->titleLocationArgs = $titleArgs;
return $this;
}
return $this;
}
/**
* Indicates the string value to replace format specifiers in the body string for localization.
*
* @param mixed $bodyArgs
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setBodyLocationArgs($bodyArgs)
{
$this->bodyLocationArgs = $bodyArgs;
/**
* Indicates the key to the body string for localization.
*
* @param string $bodyKey
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setBodyLocationKey($bodyKey)
{
$this->bodyLocationKey = $bodyKey;
return $this;
}
return $this;
}
/**
* Get title
*
* @return null|String
*/
public function getTitle()
{
return $this->title;
}
/**
* Indicates the string value to replace format specifiers in the body string for localization.
*
* @param mixed $bodyArgs
*
* @return PayloadNotificationBuilder current instance of the builder
*/
public function setBodyLocationArgs($bodyArgs)
{
$this->bodyLocationArgs = $bodyArgs;
/**
* Get body
*
* @return null|String
*/
public function getBody()
{
return $this->body;
}
return $this;
}
/**
* Get Icon
*
* @return null|String
*/
public function getIcon()
{
return $this->icon;
}
/**
* Get title.
*
* @return null|string
*/
public function getTitle()
{
return $this->title;
}
/**
* Get Sound
*
* @return null|String
*/
public function getSound()
{
return $this->sound;
}
/**
* Get body.
*
* @return null|string
*/
public function getBody()
{
return $this->body;
}
/**
* Get Badge
*
* @return null|String
*/
public function getBadge()
{
return $this->badge;
}
/**
* Get channel id for android api >= 26
*
* @return null|string
*/
public function getChannelId()
{
return $this->channelId;
}
/**
* Get Tag
*
* @return null|String
*/
public function getTag()
{
return $this->tag;
}
/**
* Get Icon.
*
* @return null|string
*/
public function getIcon()
{
return $this->icon;
}
/**
* Get Color
*
* @return null|String
*/
public function getColor()
{
return $this->color;
}
/**
* Get Sound.
*
* @return null|string
*/
public function getSound()
{
return $this->sound;
}
/**
* Get ClickAction
*
* @return null|String
*/
public function getClickAction()
{
return $this->clickAction;
}
/**
* Get Badge.
*
* @return null|string
*/
public function getBadge()
{
return $this->badge;
}
/**
* Get BodyLocationKey
*
* @return null|String
*/
public function getBodyLocationKey()
{
return $this->bodyLocationKey;
}
/**
* Get Tag.
*
* @return null|string
*/
public function getTag()
{
return $this->tag;
}
/**
* Get BodyLocationArgs
*
* @return null|String|array
*/
public function getBodyLocationArgs()
{
return $this->bodyLocationArgs;
}
/**
* Get Color.
*
* @return null|string
*/
public function getColor()
{
return $this->color;
}
/**
* Get TitleLocationKey
*
* @return string
*/
public function getTitleLocationKey()
{
return $this->titleLocationKey;
}
/**
* Get ClickAction.
*
* @return null|string
*/
public function getClickAction()
{
return $this->clickAction;
}
/**
* GetTitleLocationArgs
*
* @return null|String|array
*/
public function getTitleLocationArgs()
{
return $this->titleLocationArgs;
}
/**
* Get BodyLocationKey.
*
* @return null|string
*/
public function getBodyLocationKey()
{
return $this->bodyLocationKey;
}
/**
* Build an PayloadNotification
*
* @return PayloadNotification
*/
public function build()
{
return new PayloadNotification($this);
}
}
/**
* Get BodyLocationArgs.
*
* @return null|string|array
*/
public function getBodyLocationArgs()
{
return $this->bodyLocationArgs;
}
/**
* Get TitleLocationKey.
*
* @return string
*/
public function getTitleLocationKey()
{
return $this->titleLocationKey;
}
/**
* GetTitleLocationArgs.
*
* @return null|string|array
*/
public function getTitleLocationArgs()
{
return $this->titleLocationArgs;
}
/**
* Build an PayloadNotification.
*
* @return PayloadNotification
*/
public function build()
{
return new PayloadNotification($this);
}
}

View File

@@ -1,227 +1,226 @@
<?php namespace LaravelFCM\Message;
<?php
namespace LaravelFCM\Message;
use Closure;
use LaravelFCM\Message\Exceptions\NoTopicProvidedException;
/**
* Class Topics
* Class Topics.
*
* Create topic or a topic condition
*
* @package LaravelFCM\Message
*/
class Topics {
class Topics
{
/**
* @internal
*
* @var array of element in the condition
*/
public $conditions = [];
/**
* @internal
* @var array of element in the condition
*/
public $conditions = [];
/**
* Add a topic, this method should be called before any conditional topic.
*
* @param string $first topicName
*
* @return $this
*/
public function topic($first)
{
$this->conditions[] = compact('first');
/**
* Add a topic, this method should be called before any conditional topic
*
* @param string $first topicName
*
* @return $this
*/
public function topic($first)
{
$this->conditions[] = compact('first');
return $this;
}
return $this;
}
/**
* Add a or condition to the precedent topic set.
*
* Parenthesis is a closure
*
* Equivalent of this: **'TopicA' in topic' || 'TopicB' in topics**
*
* ```
* $topic = new Topics();
* $topic->topic('TopicA')
* ->orTopic('TopicB');
* ```
*
* Equivalent of this: **'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)**
*
* ```
* $topic = new Topics();
* $topic->topic('TopicA')
* ->andTopic(function($condition) {
* $condition->topic('TopicB')->orTopic('TopicC');
* });
* ```
*
* > Note: Only two operators per expression are supported by fcm
*
* @param string|Closure $first topicName or closure
*
* @return Topics
*/
public function orTopic($first)
{
return $this->on($first, ' || ');
}
/**
* Add a or condition to the precedent topic set
*
* Parenthesis is a closure
*
* Equivalent of this: **'TopicA' in topic' || 'TopicB' in topics**
*
* ```
* $topic = new Topics();
* $topic->topic('TopicA')
* ->orTopic('TopicB');
* ```
*
* Equivalent of this: **'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)**
*
* ```
* $topic = new Topics();
* $topic->topic('TopicA')
* ->andTopic(function($condition) {
* $condition->topic('TopicB')->orTopic('TopicC');
* });
* ```
*
* > Note: Only two operators per expression are supported by fcm
*
* @param string|Closure $first topicName or closure
*
* @return Topics
*/
public function orTopic($first)
{
return $this->on($first, ' || ');
}
/**
* Add a and condition to the precedent topic set.
*
* Parenthesis is a closure
*
* Equivalent of this: **'TopicA' in topic' && 'TopicB' in topics**
*
* ```
* $topic = new Topics();
* $topic->topic('TopicA')
* ->anTopic('TopicB');
* ```
*
* Equivalent of this: **'TopicA' in topics || ('TopicB' in topics && 'TopicC' in topics)**
*
* ```
* $topic = new Topics();
* $topic->topic('TopicA')
* ->orTopic(function($condition) {
* $condition->topic('TopicB')->AndTopic('TopicC');
* });
* ```
*
* > Note: Only two operators per expression are supported by fcm
*
* @param string|Closure $first topicName or closure
*
* @return Topics
*/
public function andTopic($first)
{
return $this->on($first, ' && ');
}
/**
* Add a and condition to the precedent topic set
*
* Parenthesis is a closure
*
* Equivalent of this: **'TopicA' in topic' && 'TopicB' in topics**
*
* ```
* $topic = new Topics();
* $topic->topic('TopicA')
* ->anTopic('TopicB');
* ```
*
* Equivalent of this: **'TopicA' in topics || ('TopicB' in topics && 'TopicC' in topics)**
*
* ```
* $topic = new Topics();
* $topic->topic('TopicA')
* ->orTopic(function($condition) {
* $condition->topic('TopicB')->AndTopic('TopicC');
* });
* ```
*
* > Note: Only two operators per expression are supported by fcm
*
* @param string|Closure $first topicName or closure
*
* @return Topics
*/
public function andTopic($first)
{
return $this->on($first, ' && ');
}
/**
* @internal
*
* @param $first
* @param $condition
*
* @return $this|Topics
*/
private function on($first, $condition)
{
if ($first instanceof Closure) {
return $this->nest($first, $condition);
}
/**
* @internal
*
* @param $first
* @param $condition
*
* @return $this|Topics
*/
private function on($first, $condition)
{
$this->conditions[] = compact('condition', 'first');
if ($first instanceof Closure) {
return $this->nest($first, $condition);
}
return $this;
}
$this->conditions[] = compact('condition', 'first');
/**
* @internal
*
* @param Closure $callback
* @param $condition
*
* @return $this
*/
public function nest(Closure $callback, $condition)
{
$topic = new static();
return $this;
}
$callback($topic);
if (count($topic->conditions)) {
$open_parenthesis = '(';
$topic = $topic->conditions;
$close_parenthesis = ')';
/**
* @internal
*
* @param Closure $callback
* @param $condition
*
* @return $this
*/
public function nest(Closure $callback, $condition)
{
$topic = new static();
$this->conditions[] = compact('condition', 'open_parenthesis', 'topic', 'close_parenthesis');
}
$callback($topic);
if (count($topic->conditions)) {
return $this;
}
$open_parenthesis = '(';
$topic = $topic->conditions;
$close_parenthesis = ')';
/**
* Transform to array.
*
* @return array|string
*
* @throws NoTopicProvided
*/
public function build()
{
$this->checkIfOneTopicExist();
$this->conditions[] = compact('condition', 'open_parenthesis', 'topic', 'close_parenthesis');
}
if ($this->hasOnlyOneTopic()) {
foreach ($this->conditions[0] as $topic) {
return '/topics/'.$topic;
}
}
return $this;
}
return [
'condition' => $this->topicsForFcm($this->conditions),
];
}
/**
* Transform to array
*
* @return array|string
* @throws NoTopicProvided
*/
public function build()
{
$this->checkIfOneTopicExist();
/**
* @internal
*
* @param $conditions
*
* @return string
*/
private function topicsForFcm($conditions)
{
$condition = '';
foreach ($conditions as $partial) {
if (array_key_exists('condition', $partial)) {
$condition .= $partial['condition'];
}
if ($this->hasOnlyOneTopic()) {
foreach ($this->conditions[ 0] as $topic) {
return '/topics/'.$topic;
}
}
if (array_key_exists('first', $partial)) {
$topic = $partial['first'];
$condition .= "'$topic' in topics";
}
return [
'condition' => $this->topicsForFcm($this->conditions)
];
}
if (array_key_exists('open_parenthesis', $partial)) {
$condition .= $partial['open_parenthesis'];
}
/**
* @internal
*
* @param $conditions
*
* @return string
*/
private function topicsForFcm($conditions)
{
$condition = "";
foreach ($conditions as $partial) {
if (array_key_exists('condition', $partial)) {
$condition .= $partial['condition'];
}
if (array_key_exists('topic', $partial)) {
$condition .= $this->topicsForFcm($partial['topic']);
}
if (array_key_exists('first', $partial)) {
$topic = $partial['first'];
$condition .= "'$topic' in topics";
}
if (array_key_exists('close_parenthesis', $partial)) {
$condition .= $partial['close_parenthesis'];
}
}
if (array_key_exists('open_parenthesis', $partial)) {
$condition .= $partial['open_parenthesis'];
}
return $condition;
}
if (array_key_exists('topic', $partial)) {
$condition .= $this->topicsForFcm($partial['topic']);
}
/**
* Check if only one topic was set.
*
* @return bool
*/
public function hasOnlyOneTopic()
{
return count($this->conditions) == 1;
}
if (array_key_exists('close_parenthesis', $partial)) {
$condition .= $partial['close_parenthesis'];
}
}
return $condition;
}
/**
* Check if only one topic was set
*
* @return bool
*/
public function hasOnlyOneTopic()
{
return count($this->conditions) == 1;
}
/**
* @internal
*
* @throws NoTopicProvidedException
*/
private function checkIfOneTopicExist()
{
if (!count($this->conditions)) {
throw new NoTopicProvidedException('At least one topic must be provided');
}
}
}
/**
* @internal
*
* @throws NoTopicProvidedException
*/
private function checkIfOneTopicExist()
{
if (!count($this->conditions)) {
throw new NoTopicProvidedException('At least one topic must be provided');
}
}
}

View File

@@ -1,63 +1,65 @@
<?php namespace LaravelFCM\Request;
<?php
namespace LaravelFCM\Request;
/**
* Class BaseRequest
*
* @package LaravelFCM\Request
* Class BaseRequest.
*/
abstract class BaseRequest {
abstract class BaseRequest
{
/**
* @internal
*
* @var \GuzzleHttp\ClientInterface
*/
protected $client;
/**
* @internal
* @var \GuzzleHttp\Client
*/
protected $client;
/**
* @internal
*
* @var array
*/
protected $config;
/**
* @internal
* @var array
*/
protected $config;
/**
* BaseRequest constructor.
*/
public function __construct()
{
$this->config = app('config')->get('fcm.http', []);
}
/**
* BaseRequest constructor.
*/
public function __construct()
{
$this->config = app('config')->get('fcm.http', []);
}
/**
* Build the header for the request.
*
* @return array
*/
protected function buildRequestHeader()
{
return [
'Authorization' => 'key='.$this->config['server_key'],
'Content-Type' => 'application/json',
'project_id' => $this->config['sender_id'],
];
}
/**
* Build the header for the request
*
* @return array
*/
protected function buildRequestHeader()
{
return [
'Authorization' => "key=".$this->config['server_key'],
'Content-Type' => "application/json",
'project_id' => $this->config['sender_id']
];
}
/**
* Build the body of the request.
*
* @return mixed
*/
abstract protected function buildBody();
/**
* Build the body of the request
*
* @return mixed
*/
protected abstract function buildBody();
/**
* Return the request in array form
*
* @return array
*/
public function build()
{
return [
'headers' => $this->buildRequestHeader(),
'json' => $this->buildBody()
];
}
}
/**
* Return the request in array form.
*
* @return array
*/
public function build()
{
return [
'headers' => $this->buildRequestHeader(),
'json' => $this->buildBody(),
];
}
}

View File

@@ -1,66 +1,70 @@
<?php namespace LaravelFCM\Request;
<?php
namespace LaravelFCM\Request;
/**
* Class GroupRequest
*
* @package LaravelFCM\Request
* Class GroupRequest.
*/
class GroupRequest extends BaseRequest{
class GroupRequest extends BaseRequest
{
/**
* @internal
*
* @var string
*/
protected $operation;
/**
* @internal
* @var string
*/
protected $operation;
/**
* @internal
*
* @var string
*/
protected $notificationKeyName;
/**
* @internal
* @var string
*/
protected $notificationKeyName;
/**
* @internal
*
* @var string
*/
protected $notificationKey;
/**
* @internal
* @var string
*/
protected $notificationKey;
/**
* @internal
*
* @var array
*/
protected $registrationIds;
/**
* @internal
* @var array
*/
protected $registrationIds;
/**
* GroupRequest constructor.
*
* @param $operation
* @param $notificationKeyName
* @param $notificationKey
* @param $registrationIds
*/
public function __construct($operation, $notificationKeyName, $notificationKey, $registrationIds)
{
parent::__construct();
/**
* GroupRequest constructor.
*
* @param $operation
* @param $notificationKeyName
* @param $notificationKey
* @param $registrationIds
*/
public function __construct($operation, $notificationKeyName, $notificationKey, $registrationIds)
{
parent::__construct();
$this->operation = $operation;
$this->notificationKeyName = $notificationKeyName;
$this->notificationKey = $notificationKey;
$this->registrationIds = $registrationIds;
}
$this->operation = $operation;
$this->notificationKeyName = $notificationKeyName;
$this->notificationKey = $notificationKey;
$this->registrationIds = $registrationIds;
}
/**
* Build the header for the request
*
* @return array
*/
protected function buildBody()
{
return [
'operation' => $this->operation,
'notification_key_name' => $this->notificationKeyName,
'notification_key' => $this->notificationKey,
'registration_ids' => $this->registrationIds
];
}
}
/**
* Build the header for the request.
*
* @return array
*/
protected function buildBody()
{
return [
'operation' => $this->operation,
'notification_key_name' => $this->notificationKeyName,
'notification_key' => $this->notificationKey,
'registration_ids' => $this->registrationIds,
];
}
}

View File

@@ -1,4 +1,6 @@
<?php namespace LaravelFCM\Request;
<?php
namespace LaravelFCM\Request;
use LaravelFCM\Message\Topics;
use LaravelFCM\Message\Options;
@@ -6,143 +8,144 @@ use LaravelFCM\Message\PayloadData;
use LaravelFCM\Message\PayloadNotification;
/**
* Class Request
*
* @package LaravelFCM\Request
* Class Request.
*/
class Request extends BaseRequest{
class Request extends BaseRequest
{
/**
* @internal
*
* @var string|array
*/
protected $to;
/**
* @internal
* @var string|array
*/
protected $to;
/**
* @internal
*
* @var Options
*/
protected $options;
/**
* @internal
* @var Options
*/
protected $options;
/**
* @internal
*
* @var PayloadNotification
*/
protected $notification;
/**
* @internal
* @var PayloadNotification
*/
protected $notification;
/**
* @internal
*
* @var PayloadData
*/
protected $data;
/**
* @internal
* @var PayloadData
*/
protected $data;
/**
* @internal
*
* @var Topics|null
*/
protected $topic;
/**
* @internal
* @var Topics|null
*/
protected $topic;
/**
* Request constructor.
*
* @param $to
* @param Options $options
* @param PayloadNotification $notification
* @param PayloadData $data
* @param Topics|null $topic
*/
public function __construct($to, Options $options = null, PayloadNotification $notification = null, PayloadData $data = null, Topics $topic = null)
{
parent::__construct();
/**
* Request constructor.
*
* @param $to
* @param Options $options
* @param PayloadNotification $notification
* @param PayloadData $data
* @param Topics|null $topic
*/
public function __construct($to, Options $options = null, PayloadNotification $notification = null, PayloadData $data = null, Topics $topic = null)
{
parent::__construct();
$this->to = $to;
$this->options = $options;
$this->notification = $notification;
$this->data = $data;
$this->topic = $topic;
}
$this->to = $to;
$this->options = $options;
$this->notification = $notification;
$this->data = $data;
$this->topic = $topic;
}
/**
* Build the body for the request.
*
* @return array
*/
protected function buildBody()
{
$message = [
'to' => $this->getTo(),
'registration_ids' => $this->getRegistrationIds(),
'notification' => $this->getNotification(),
'data' => $this->getData(),
];
/**
* Build the body for the request
*
* @return array
*/
protected function buildBody()
{
$message = [
'to' => $this->getTo(),
'registration_ids' => $this->getRegistrationIds(),
'notification' => $this->getNotification(),
'data' => $this->getData()
];
$message = array_merge($message, $this->getOptions());
$message = array_merge($message, $this->getOptions());
// remove null entries
return array_filter($message);
}
// remove null entries
return array_filter($message);
}
/**
* get to key transformed.
*
* @return array|null|string
*/
protected function getTo()
{
$to = is_array($this->to) ? null : $this->to;
/**
* get to key transformed
*
* @return array|null|string
*/
protected function getTo()
{
$to = is_array($this->to) ? null : $this->to;
if ($this->topic && $this->topic->hasOnlyOneTopic()) {
$to = $this->topic->build();
}
if ($this->topic && $this->topic->hasOnlyOneTopic()) {
$to = $this->topic->build();
}
return $to;
}
return $to;
}
/**
* get registrationIds transformed.
*
* @return array|null
*/
protected function getRegistrationIds()
{
return is_array($this->to) ? $this->to : null;
}
/**
* get registrationIds transformed
*
* @return array|null
*/
protected function getRegistrationIds()
{
return is_array($this->to) ? $this->to : null;
}
/**
* get Options transformed.
*
* @return array
*/
protected function getOptions()
{
$options = $this->options ? $this->options->toArray() : [];
/**
* get Options transformed
*
* @return array
*/
protected function getOptions()
{
$options = $this->options ? $this->options->toArray() : [];
if ($this->topic && !$this->topic->hasOnlyOneTopic()) {
$options = array_merge($options, $this->topic->build());
}
if ($this->topic && !$this->topic->hasOnlyOneTopic()) {
return $options;
}
$options = array_merge($options, $this->topic->build());
}
/**
* get notification transformed.
*
* @return array|null
*/
protected function getNotification()
{
return $this->notification ? $this->notification->toArray() : null;
}
return $options;
}
/**
* get notification transformed
*
* @return array|null
*/
protected function getNotification()
{
return $this->notification ? $this->notification->toArray() : null;
}
/**
* get data transformed
*
* @return array|null
*/
protected function getData()
{
return $this->data ? $this->data->toArray() : null;
}
}
/**
* get data transformed.
*
* @return array|null
*/
protected function getData()
{
return $this->data ? $this->data->toArray() : null;
}
}

View File

@@ -1,71 +1,75 @@
<?php namespace LaravelFCM\Response;
<?php
use GuzzleHttp\Psr7\Response as GuzzleResponse;
namespace LaravelFCM\Response;
use Psr\Http\Message\ResponseInterface;
use LaravelFCM\Response\Exceptions\ServerResponseException;
use LaravelFCM\Response\Exceptions\InvalidRequestException;
use LaravelFCM\Response\Exceptions\UnauthorizedRequestException;
/**
* Class BaseResponse
*
* @package LaravelFCM\Response
* Class BaseResponse.
*/
abstract class BaseResponse {
abstract class BaseResponse
{
const SUCCESS = 'success';
const FAILURE = 'failure';
const ERROR = 'error';
const MESSAGE_ID = 'message_id';
const SUCCESS = 'success';
const FAILURE = 'failure';
const ERROR = "error";
const MESSAGE_ID = "message_id";
/**
* @var bool
*/
protected $logEnabled = false;
/**
* BaseResponse constructor.
*
* @param GuzzleResponse $response
*/
public function __construct(GuzzleResponse $response)
{
$this->isJsonResponse($response);
/**
* BaseResponse constructor.
*
* @param \Psr\Http\Message\ResponseInterface $response
*/
public function __construct(ResponseInterface $response)
{
$this->isJsonResponse($response);
$this->logEnabled = app('config')->get('fcm.log_enabled', false);
$responseInJson = json_decode($response->getBody(), true);
$this->parseResponse($responseInJson);
}
$responseInJson = json_decode($response->getBody(), true);
$this->parseResponse($responseInJson);
}
/**
* Check if the response given by fcm is parsable.
*
* @param \Psr\Http\Message\ResponseInterface $response
*
* @throws InvalidRequestException
* @throws ServerResponseException
* @throws UnauthorizedRequestException
*/
private function isJsonResponse(ResponseInterface $response)
{
if ($response->getStatusCode() == 200) {
return;
}
/**
* Check if the response given by fcm is parsable
*
* @param GuzzleResponse $response
*
* @throws InvalidRequestException
* @throws ServerResponseException
* @throws UnauthorizedRequestException
*/
private function isJsonResponse(GuzzleResponse $response)
{
if ($response->getStatusCode() == 200) {
return;
}
if ($response->getStatusCode() == 400) {
throw new InvalidRequestException($response);
}
if ($response->getStatusCode() == 400) {
throw new InvalidRequestException($response);
}
if ($response->getStatusCode() == 401) {
throw new UnauthorizedRequestException($response);
}
if ($response->getStatusCode() == 401) {
throw new UnauthorizedRequestException($response);
}
throw new ServerResponseException($response);
}
throw new ServerResponseException($response);
}
/**
* parse the response.
*
* @param array $responseInJson
*/
abstract protected function parseResponse($responseInJson);
/**
* parse the response
*
* @param array $responseInJson
*/
protected abstract function parseResponse($responseInJson);
/**
* Log the response
*/
protected abstract function logResponse();
}
/**
* Log the response.
*/
abstract protected function logResponse();
}

View File

@@ -1,410 +1,413 @@
<?php namespace LaravelFCM\Response;
<?php
namespace LaravelFCM\Response;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use GuzzleHttp\Psr7\Response as GuzzleResponse;
use Psr\Http\Message\ResponseInterface;
/**
* Class DownstreamResponse
*
* @package LaravelFCM\Response
* Class DownstreamResponse.
*/
class DownstreamResponse extends BaseResponse implements DownstreamResponseContract{
class DownstreamResponse extends BaseResponse implements DownstreamResponseContract
{
const MULTICAST_ID = 'multicast_id';
const CANONICAL_IDS = 'canonical_ids';
const RESULTS = 'results';
const MULTICAST_ID = 'multicast_id';
const CANONICAL_IDS = "canonical_ids";
const RESULTS = "results";
const MISSING_REGISTRATION = 'MissingRegistration';
const MESSAGE_ID = 'message_id';
const REGISTRATION_ID = 'registration_id';
const NOT_REGISTERED = 'NotRegistered';
const INVALID_REGISTRATION = 'InvalidRegistration';
const UNAVAILABLE = 'Unavailable';
const DEVICE_MESSAGE_RATE_EXCEEDED = 'DeviceMessageRateExceeded';
const INTERNAL_SERVER_ERROR = 'InternalServerError';
const MISSING_REGISTRATION = "MissingRegistration";
const MESSAGE_ID = "message_id";
const REGISTRATION_ID = "registration_id";
const NOT_REGISTERED = "NotRegistered";
const INVALID_REGISTRATION = "InvalidRegistration";
const UNAVAILABLE = "Unavailable";
const DEVICE_MESSAGE_RATE_EXCEEDED = "DeviceMessageRateExceeded";
const INTERNAL_SERVER_ERROR = "InternalServerError";
/**
* @internal
*
* @var int
*/
protected $numberTokensSuccess = 0;
/**
* @internal
*
* @var int
*/
protected $numberTokensSuccess = 0;
/**
* @internal
*
* @var int
*/
protected $numberTokensFailure = 0;
/**
* @internal
*
* @var int
*/
protected $numberTokensFailure = 0;
/**
* @internal
*
* @var int
*/
protected $numberTokenModify = 0;
/**
* @internal
*
* @var int
*/
protected $numberTokenModify = 0;
/**
* @internal
*
* @var
*/
protected $messageId;
/**
* @internal
*
* @var
*/
protected $messageId;
/**
* @internal
*
* @var array
*/
protected $tokensToDelete = [];
/**
* @internal
*
* @var array
*/
protected $tokensToDelete = [];
/**
* @internal
*
* @var array
*/
protected $tokensToModify = [];
/**
* @internal
*
* @var array
*/
protected $tokensToRetry = [];
/**
* @internal
*
* @var array
*/
/**
* @internal
*
* @var array
*/
protected $tokensWithError = [];
protected $tokensToModify = [];
/**
* @internal
*
* @var array
*/
/**
* @internal
*
* @var bool
*/
protected $hasMissingToken = false;
protected $tokensToRetry = [];
/**
* @internal
*
* @var array
*/
private $tokens;
/**
* @internal
*
* @var array
*/
protected $tokensWithError = [];
/**
* DownstreamResponse constructor.
*
* @param \Psr\Http\Message\ResponseInterface $response
* @param $tokens
*/
public function __construct(ResponseInterface $response, $tokens)
{
$this->tokens = is_string($tokens) ? [$tokens] : $tokens;
/**
* @internal
* @var bool
*/
protected $hasMissingToken = false;
parent::__construct($response);
}
/**
* @internal
*
* @var array
*/
private $tokens;
/**
* Parse the response.
*
* @param $responseInJson
*/
protected function parseResponse($responseInJson)
{
$this->parse($responseInJson);
/**
* DownstreamResponse constructor.
*
* @param GuzzleResponse $response
* @param $tokens
*/
public function __construct(GuzzleResponse $response, $tokens)
{
$this->tokens = is_string($tokens) ? [$tokens] : $tokens;
if ($this->needResultParsing($responseInJson)) {
$this->parseResult($responseInJson);
}
parent::__construct($response);
}
if ($this->logEnabled) {
$this->logResponse();
}
}
/**
* Parse the response
*
* @param $responseInJson
*/
protected function parseResponse($responseInJson)
{
$this->parse($responseInJson);
/**
* @internal
*
* @param $responseInJson
*/
private function parse($responseInJson)
{
if (array_key_exists(self::MULTICAST_ID, $responseInJson)) {
$this->messageId;
}
if ($this->needResultParsing($responseInJson)) {
$this->parseResult($responseInJson);
}
if (array_key_exists(self::SUCCESS, $responseInJson)) {
$this->numberTokensSuccess = $responseInJson[self::SUCCESS];
}
$this->logResponse();
}
if (array_key_exists(self::FAILURE, $responseInJson)) {
$this->numberTokensFailure = $responseInJson[self::FAILURE];
}
/**
* @internal
*
* @param $responseInJson
*/
private function parse($responseInJson)
{
if (array_key_exists(self::MULTICAST_ID, $responseInJson)) {
$this->messageId;
}
if (array_key_exists(self::CANONICAL_IDS, $responseInJson)) {
$this->numberTokenModify = $responseInJson[self::CANONICAL_IDS];
}
}
if (array_key_exists(self::SUCCESS, $responseInJson)) {
$this->numberTokensSuccess = $responseInJson[self::SUCCESS];
}
/**
* @internal
*
* @param $responseInJson
*/
private function parseResult($responseInJson)
{
foreach ($responseInJson[self::RESULTS] as $index => $result) {
if (!$this->isSent($result)) {
if (!$this->needToBeModify($index, $result)) {
if (!$this->needToBeDeleted($index, $result) && !$this->needToResend($index, $result) && !$this->checkMissingToken($result)) {
$this->needToAddError($index, $result);
}
}
}
}
}
if (array_key_exists(self::FAILURE, $responseInJson)) {
$this->numberTokensFailure = $responseInJson[self::FAILURE];
}
/**
* @internal
*
* @param $responseInJson
*
* @return bool
*/
private function needResultParsing($responseInJson)
{
return array_key_exists(self::RESULTS, $responseInJson) && ($this->numberTokensFailure > 0 || $this->numberTokenModify > 0);
}
if (array_key_exists(self::CANONICAL_IDS, $responseInJson)) {
$this->numberTokenModify = $responseInJson[self::CANONICAL_IDS];
}
}
/**
* @internal
*
* @param $results
*
* @return bool
*/
private function isSent($results)
{
return array_key_exists(self::MESSAGE_ID, $results) && !array_key_exists(self::REGISTRATION_ID, $results);
}
/**
* @internal
*
* @param $responseInJson
*/
private function parseResult($responseInJson)
{
foreach ($responseInJson[self::RESULTS] as $index => $result) {
/**
* @internal
*
* @param $index
* @param $result
*
* @return bool
*/
private function needToBeModify($index, $result)
{
if (array_key_exists(self::MESSAGE_ID, $result) && array_key_exists(self::REGISTRATION_ID, $result)) {
if ($this->tokens[$index]) {
$this->tokensToModify[$this->tokens[$index]] = $result[self::REGISTRATION_ID];
}
if (!$this->isSent($result)) {
if (!$this->needToBeModify($index, $result)) {
if (!$this->needToBeDeleted($index, $result) && !$this->needToResend($index, $result) && !$this->checkMissingToken($result)) {
$this->needToAddError($index, $result);
}
};
}
}
}
return true;
}
/**
* @internal
*
* @param $responseInJson
*
* @return bool
*/
private function needResultParsing($responseInJson)
{
return array_key_exists(self::RESULTS, $responseInJson) && ($this->numberTokensFailure > 0 || $this->numberTokenModify > 0);
}
return false;
}
/**
* @internal
* @param $results
*
* @return bool
*/
private function isSent($results)
{
return (array_key_exists(self::MESSAGE_ID, $results) && !array_key_exists(self::REGISTRATION_ID, $results));
}
/**
* @internal
*
* @param $index
* @param $result
*
* @return bool
*/
private function needToBeDeleted($index, $result)
{
if (array_key_exists(self::ERROR, $result) &&
(in_array(self::NOT_REGISTERED, $result) || in_array(self::INVALID_REGISTRATION, $result))) {
if ($this->tokens[$index]) {
$this->tokensToDelete[] = $this->tokens[$index];
}
/**
* @internal
*
* @param $index
* @param $result
*
* @return bool
*/
private function needToBeModify($index, $result)
{
if (array_key_exists(self::MESSAGE_ID, $result) && array_key_exists(self::REGISTRATION_ID, $result)) {
if ($this->tokens[$index]) {
$this->tokensToModify[$this->tokens[$index]] = $result[self::REGISTRATION_ID];
}
return true;
}
return true;
}
return false;
}
return false;
}
/**
* @internal
*
* @param $index
* @param $result
*
* @return bool
*/
private function needToResend($index, $result)
{
if (array_key_exists(self::ERROR, $result) && (in_array(self::UNAVAILABLE, $result) || in_array(self::DEVICE_MESSAGE_RATE_EXCEEDED, $result) || in_array(self::INTERNAL_SERVER_ERROR, $result))) {
if ($this->tokens[$index]) {
$this->tokensToRetry[] = $this->tokens[$index];
}
/**
* @internal
*
* @param $index
* @param $result
*
* @return bool
*/
private function needToBeDeleted($index, $result)
{
if (array_key_exists(self::ERROR, $result) &&
(in_array(self::NOT_REGISTERED, $result) || in_array(self::INVALID_REGISTRATION, $result))) {
return true;
}
if ($this->tokens[$index]) {
$this->tokensToDelete[] = $this->tokens[$index];
}
return false;
}
return true;
}
return false;
}
/**
* @internal
*
* @param $result
*
* @return bool
*/
private function checkMissingToken($result)
{
$hasMissingToken = (array_key_exists(self::ERROR, $result) && in_array(self::MISSING_REGISTRATION, $result));
/**
* @internal
*
* @param $index
* @param $result
*
* @return bool
*/
private function needToResend($index, $result)
{
if (array_key_exists(self::ERROR, $result) && (in_array(self::UNAVAILABLE, $result) || in_array(self::DEVICE_MESSAGE_RATE_EXCEEDED, $result) || in_array(self::INTERNAL_SERVER_ERROR, $result))) {
if ($this->tokens[$index]) {
$this->tokensToRetry[] = $this->tokens[$index];
}
$this->hasMissingToken = (bool) ($this->hasMissingToken | $hasMissingToken);
return true;
}
return false;
}
return $hasMissingToken;
}
/**
* @internal
*
* @param $result
*
* @return bool
*/
private function checkMissingToken($result)
{
$hasMissingToken = (array_key_exists(self::ERROR, $result) && in_array(self::MISSING_REGISTRATION, $result));
/**
* @internal
*
* @param $index
* @param $result
*/
private function needToAddError($index, $result)
{
if (array_key_exists(self::ERROR, $result)) {
if ($this->tokens[$index]) {
$this->tokensWithError[$this->tokens[$index]] = $result[self::ERROR];
}
}
}
$this->hasMissingToken = (boolean) ($this->hasMissingToken | $hasMissingToken);
/**
* @internal
*/
protected function logResponse()
{
$logger = new Logger('Laravel-FCM');
$logger->pushHandler(new StreamHandler(storage_path('logs/laravel-fcm.log')));
return $hasMissingToken;
}
$logMessage = 'notification send to '.count($this->tokens).' devices'.PHP_EOL;
$logMessage .= 'success: '.$this->numberTokensSuccess.PHP_EOL;
$logMessage .= 'failures: '.$this->numberTokensFailure.PHP_EOL;
$logMessage .= 'number of modified token : '.$this->numberTokenModify.PHP_EOL;
/**
* @internal
*
* @param $index
* @param $result
*/
private function needToAddError($index, $result)
{
if (array_key_exists(self::ERROR, $result)) {
if ($this->tokens[$index]) {
$this->tokensWithError[$this->tokens[$index]] = $result[self::ERROR];
}
}
}
$logger->info($logMessage);
}
/**
* @internal
*/
protected function logResponse()
{
$logger = new Logger('Laravel-FCM');
$logger->pushHandler(new StreamHandler(storage_path('logs/laravel-fcm.log')));
/**
* Merge two response.
*
* @param DownstreamResponse $response
*/
public function merge(DownstreamResponse $response)
{
$this->numberTokensSuccess += $response->numberSuccess();
$this->numberTokensFailure += $response->numberFailure();
$this->numberTokenModify += $response->numberModification();
$logMessage = "notification send to ".count($this->tokens)." devices".PHP_EOL;
$logMessage .= "success: ".$this->numberTokensSuccess.PHP_EOL;
$logMessage .= "failures: ".$this->numberTokensFailure.PHP_EOL;
$logMessage .= "number of modified token : ".$this->numberTokenModify.PHP_EOL;
$this->tokensToDelete = array_merge($this->tokensToDelete, $response->tokensToDelete());
$this->tokensToModify = array_merge($this->tokensToModify, $response->tokensToModify());
$this->tokensToRetry = array_merge($this->tokensToRetry, $response->tokensToRetry());
$this->tokensWithError = array_merge($this->tokensWithError, $response->tokensWithError());
}
$logger->info($logMessage);
}
/**
* Get the number of device reached with success.
*
* @return int
*/
public function numberSuccess()
{
return $this->numberTokensSuccess;
}
/**
* Merge two response
*
* @param DownstreamResponse $response
*/
public function merge(DownstreamResponse $response)
{
$this->numberTokensSuccess += $response->numberSuccess();
$this->numberTokensFailure += $response->numberFailure();
$this->numberTokenModify += $response->numberModification();
/**
* Get the number of device which thrown an error.
*
* @return int
*/
public function numberFailure()
{
return $this->numberTokensFailure;
}
$this->tokensToDelete = array_merge($this->tokensToDelete, $response->tokensToDelete());
$this->tokensToModify = array_merge($this->tokensToModify, $response->tokensToModify());
$this->tokensToRetry = array_merge($this->tokensToRetry, $response->tokensToRetry());
$this->tokensWithError = array_merge($this->tokensWithError, $response->tokensWithError());
}
/**
* Get the number of device that you need to modify their token.
*
* @return int
*/
public function numberModification()
{
return $this->numberTokenModify;
}
/**
* Get the number of device reached with success
* @return int
*/
public function numberSuccess()
{
return $this->numberTokensSuccess;
}
/**
* get token to delete.
*
* remove all tokens returned by this method in your database
*
* @return array
*/
public function tokensToDelete()
{
return $this->tokensToDelete;
}
/**
* Get the number of device which thrown an error
*
* @return int
*/
public function numberFailure()
{
return $this->numberTokensFailure;
}
/**
* get token to modify.
*
* key: oldToken
* value: new token
*
* find the old token in your database and replace it with the new one
*
* @return array
*/
public function tokensToModify()
{
return $this->tokensToModify;
}
/**
* Get the number of device that you need to modify their token
*
* @return int
*/
public function numberModification()
{
return $this->numberTokenModify;
}
/**
* Get tokens that you should resend using exponential backoof.
*
* @return array
*/
public function tokensToRetry()
{
return $this->tokensToRetry;
}
/**
* get token to delete
*
* remove all tokens returned by this method in your database
*
* @return array
*/
public function tokensToDelete()
{
return $this->tokensToDelete;
}
/**
* Get tokens that thrown an error.
*
* key : token
* value : error
*
* In production, remove these tokens from you database
*
* @return array
*/
public function tokensWithError()
{
return $this->tokensWithError;
}
/**
* get token to modify
*
* key: oldToken
* value: new token
*
* find the old token in your database and replace it with the new one
*
* @return array
*/
public function tokensToModify()
{
return $this->tokensToModify;
}
/**
* Get tokens that you should resend using exponential backoof
*
* @return array
*/
public function tokensToRetry()
{
return $this->tokensToRetry;
}
/**
* Get tokens that thrown an error
*
* key : token
* value : error
*
* In production, remove these tokens from you database
*
* @return array
*/
public function tokensWithError()
{
return $this->tokensWithError;
}
/**
* check if missing tokens was given to the request
* If true, remove all the empty token in your database
*
* @return bool
*/
public function hasMissingToken()
{
return $this->hasMissingToken;
}
}
/**
* check if missing tokens was given to the request
* If true, remove all the empty token in your database.
*
* @return bool
*/
public function hasMissingToken()
{
return $this->hasMissingToken;
}
}

View File

@@ -1,85 +1,85 @@
<?php namespace LaravelFCM\Response;
<?php
namespace LaravelFCM\Response;
/**
* Interface DownstreamResponseContract
*
* @package LaravelFCM\Response
* Interface DownstreamResponseContract.
*/
interface DownstreamResponseContract {
interface DownstreamResponseContract
{
/**
* Merge two response.
*
* @param DownstreamResponse $response
*/
public function merge(DownstreamResponse $response);
/**
* Merge two response
*
* @param DownstreamResponse $response
*/
public function merge(DownstreamResponse $response);
/**
* Get the number of device reached with success.
*
* @return int
*/
public function numberSuccess();
/**
* Get the number of device reached with success
* @return int
*/
public function numberSuccess();
/**
* Get the number of device which thrown an error.
*
* @return int
*/
public function numberFailure();
/**
* Get the number of device which thrown an error
*
* @return int
*/
public function numberFailure();
/**
* Get the number of device that you need to modify their token.
*
* @return int
*/
public function numberModification();
/**
* Get the number of device that you need to modify their token
*
* @return int
*/
public function numberModification();
/**
* get token to delete.
*
* remove all tokens returned by this method in your database
*
* @return array
*/
public function tokensToDelete();
/**
* get token to delete
*
* remove all tokens returned by this method in your database
*
* @return array
*/
public function tokensToDelete();
/**
* get token to modify.
*
* key: oldToken
* value: new token
*
* find the old token in your database and replace it with the new one
*
* @return array
*/
public function tokensToModify();
/**
* get token to modify
*
* key: oldToken
* value: new token
*
* find the old token in your database and replace it with the new one
*
* @return array
*/
public function tokensToModify();
/**
* Get tokens that you should resend using exponential backoof.
*
* @return array
*/
public function tokensToRetry();
/**
* Get tokens that you should resend using exponential backoof
*
* @return array
*/
public function tokensToRetry();
/**
* Get tokens that thrown an error.
*
* key : token
* value : error
*
* In production, remove these tokens from you database
*
* @return array
*/
public function tokensWithError();
/**
* Get tokens that thrown an error
*
* key : token
* value : error
*
* In production, remove these tokens from you database
*
* @return array
*/
public function tokensWithError();
/**
* check if missing tokens was given to the request
* If true, remove all the empty token in your database
*
* @return bool
*/
public function hasMissingToken();
}
/**
* check if missing tokens was given to the request
* If true, remove all the empty token in your database.
*
* @return bool
*/
public function hasMissingToken();
}

View File

@@ -1,25 +1,25 @@
<?php namespace LaravelFCM\Response\Exceptions;
<?php
namespace LaravelFCM\Response\Exceptions;
use Exception;
use GuzzleHttp\Psr7\Response as GuzzleResponse;
use Psr\Http\Message\ResponseInterface;
/**
* Class InvalidRequestException
*
* @package LaravelFCM\Response\Exceptions
* Class InvalidRequestException.
*/
class InvalidRequestException extends Exception {
class InvalidRequestException extends Exception
{
/**
* InvalidRequestException constructor.
*
* @param \Psr\Http\Message\ResponseInterface $response
*/
public function __construct(ResponseInterface $response)
{
$code = $response->getStatusCode();
$responseBody = $response->getBody()->getContents();
/**
* InvalidRequestException constructor.
*
* @param GuzzleResponse $response
*/
public function __construct(GuzzleResponse $response)
{
$code = $response->getStatusCode();
$responseBody = $response->getBody()->getContents();
parent::__construct($responseBody, $code);
}
}
parent::__construct($responseBody, $code);
}
}

View File

@@ -1,36 +1,37 @@
<?php namespace LaravelFCM\Response\Exceptions;
<?php
namespace LaravelFCM\Response\Exceptions;
use Exception;
use GuzzleHttp\Psr7\Response as GuzzleResponse;
use Psr\Http\Message\ResponseInterface;
/**
* Class ServerResponseException
*
* @package LaravelFCM\Response\Exceptions
* Class ServerResponseException.
*/
class ServerResponseException extends Exception {
class ServerResponseException extends Exception
{
/**
* retry after.
*
* @var int
*/
public $retryAfter;
/**
* retry after
* @var int
*/
public $retryAfter;
/**
* ServerResponseException constructor.
*
* @param \Psr\Http\Message\ResponseInterface $response
*/
public function __construct(ResponseInterface $response)
{
$code = $response->getStatusCode();
$responseHeader = $response->getHeaders();
$responseBody = $response->getBody()->getContents();
/**
* ServerResponseException constructor.
*
* @param GuzzleResponse $response
*/
public function __construct(GuzzleResponse $response)
{
$code = $response->getStatusCode();
$responseHeader = $response->getHeaders();
$responseBody = $response->getBody()->getContents();
if (array_keys($responseHeader, 'Retry-After')) {
$this->retryAfter = $responseHeader['Retry-After'];
}
if (array_keys($responseHeader, "Retry-After")) {
$this->retryAfter = $responseHeader["Retry-After"];
}
parent::__construct($responseBody, $code);
}
}
parent::__construct($responseBody, $code);
}
}

View File

@@ -1,24 +1,24 @@
<?php namespace LaravelFCM\Response\Exceptions;
<?php
namespace LaravelFCM\Response\Exceptions;
use Exception;
use GuzzleHttp\Psr7\Response as GuzzleResponse;
use Psr\Http\Message\ResponseInterface;
/**
* Class UnauthorizedRequestException
*
* @package LaravelFCM\Response\Exceptions
* Class UnauthorizedRequestException.
*/
class UnauthorizedRequestException extends Exception {
class UnauthorizedRequestException extends Exception
{
/**
* UnauthorizedRequestException constructor.
*
* @param \Psr\Http\Message\ResponseInterface $response
*/
public function __construct(ResponseInterface $response)
{
$code = $response->getStatusCode();
/**
* UnauthorizedRequestException constructor.
*
* @param GuzzleResponse $response
*/
public function __construct(GuzzleResponse $response)
{
$code = $response->getStatusCode();
parent::__construct('FCM_SENDER_ID or FCM_SERVER_KEY are invalid', $code);
}
}
parent::__construct('FCM_SENDER_ID or FCM_SERVER_KEY are invalid', $code);
}
}

View File

@@ -1,137 +1,148 @@
<?php namespace LaravelFCM\Response;
<?php
namespace LaravelFCM\Response;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use GuzzleHttp\Psr7\Response as GuzzleResponse;
use Psr\Http\Message\ResponseInterface;
/**
* Class GroupResponse
*
* @package LaravelFCM\Response
* Class GroupResponse.
*/
class GroupResponse extends BaseResponse implements GroupResponseContract{
class GroupResponse extends BaseResponse implements GroupResponseContract
{
const FAILED_REGISTRATION_IDS = 'failed_registration_ids';
const FAILED_REGISTRATION_IDS = "failed_registration_ids";
/**
* @internal
*
* @var int
*/
protected $numberTokensSuccess = 0;
/**
* @internal
* @var int
*/
protected $numberTokensSuccess = 0;
/**
* @internal
*
* @var int
*/
protected $numberTokensFailure = 0;
/**
* @internal
* @var int
*/
protected $numberTokensFailure = 0;
/**
* @internal
*
* @var array
*/
protected $tokensFailed = [];
/**
* @internal
* @var array
*/
protected $tokensFailed = [];
/**
* @internal
*
* @var string
*/
protected $to;
/**
* @internal
* @var string
*/
protected $to;
/**
* GroupResponse constructor.
*
* @param \Psr\Http\Message\ResponseInterface $response
* @param $to
*/
public function __construct(ResponseInterface $response, $to)
{
$this->to = $to;
parent::__construct($response);
}
/**
* GroupResponse constructor.
*
* @param GuzzleResponse $response
* @param $to
*/
public function __construct(GuzzleResponse $response, $to)
{
$this->to = $to;
parent::__construct($response);
}
/**
* parse the response.
*
* @param $responseInJson
*/
protected function parseResponse($responseInJson)
{
if ($this->parse($responseInJson)) {
$this->parseFailed($responseInJson);
}
/**
* parse the response
*
* @param $responseInJson
*/
protected function parseResponse($responseInJson)
{
if ($this->parse($responseInJson)) {
$this->parseFailed($responseInJson);
}
}
if ($this->logEnabled) {
$this->logResponse();
}
}
/**
* Log the response
*/
protected function logResponse()
{
$logger = new Logger('Laravel-FCM');
$logger->pushHandler(new StreamHandler(storage_path('logs/laravel-fcm.log')));
/**
* Log the response.
*/
protected function logResponse()
{
$logger = new Logger('Laravel-FCM');
$logger->pushHandler(new StreamHandler(storage_path('logs/laravel-fcm.log')));
$logMessage = "notification send to group: $this->to";
$logMessage .= "with $this->numberTokensSuccess success and $this->Failure failure";
$logger->info($logMessage);
}
$logMessage = "notification send to group: $this->to";
$logMessage .= "with $this->numberTokensSuccess success and $this->numberTokensFailure";
/**
* @internal
* @param $responseInJson
*
* @return bool
*/
private function parse($responseInJson)
{
if (array_key_exists(self::SUCCESS, $responseInJson)) {
$this->numberTokensSuccess = $responseInJson[self::SUCCESS];
}
if (array_key_exists(self::FAILURE, $responseInJson)) {
$this->numberTokensFailure = $responseInJson[self::FAILURE];
}
$logger->info($logMessage);
}
return $this->numberTokensFailure > 0;
}
/**
* @internal
*
* @param $responseInJson
*
* @return bool
*/
private function parse($responseInJson)
{
if (array_key_exists(self::SUCCESS, $responseInJson)) {
$this->numberTokensSuccess = $responseInJson[self::SUCCESS];
}
if (array_key_exists(self::FAILURE, $responseInJson)) {
$this->numberTokensFailure = $responseInJson[self::FAILURE];
}
/**
* @internal
* @param $responseInJson
*/
private function parseFailed($responseInJson)
{
if (array_key_exists(self::FAILED_REGISTRATION_IDS, $responseInJson)) {
foreach ($responseInJson[self::FAILED_REGISTRATION_IDS] as $registrationId) {
$this->tokensFailed[] = $registrationId;
}
}
}
return $this->numberTokensFailure > 0;
}
/**
* Get the number of device reached with success
* @return int
*/
public function numberSuccess()
{
return $this->numberTokensSuccess;
}
/**
* @internal
*
* @param $responseInJson
*/
private function parseFailed($responseInJson)
{
if (array_key_exists(self::FAILED_REGISTRATION_IDS, $responseInJson)) {
foreach ($responseInJson[self::FAILED_REGISTRATION_IDS] as $registrationId) {
$this->tokensFailed[] = $registrationId;
}
}
}
/**
* Get the number of device which thrown an error
*
* @return int
*/
public function numberFailure()
{
return $this->numberTokensFailure;
}
/**
* Get the number of device reached with success.
*
* @return int
*/
public function numberSuccess()
{
return $this->numberTokensSuccess;
}
/**
* Get all token in group that fcm cannot reach
*
* @return array
*/
public function tokensFailed()
{
return $this->tokensFailed;
}
}
/**
* Get the number of device which thrown an error.
*
* @return int
*/
public function numberFailure()
{
return $this->numberTokensFailure;
}
/**
* Get all token in group that fcm cannot reach.
*
* @return array
*/
public function tokensFailed()
{
return $this->tokensFailed;
}
}

View File

@@ -1,30 +1,30 @@
<?php namespace LaravelFCM\Response;
<?php
namespace LaravelFCM\Response;
/**
* Interface GroupResponseContract
*
* @package LaravelFCM\Response
* Interface GroupResponseContract.
*/
interface GroupResponseContract {
interface GroupResponseContract
{
/**
* Get the number of device reached with success.
*
* @return int
*/
public function numberSuccess();
/**
* Get the number of device reached with success
* @return int
*/
public function numberSuccess();
/**
* Get the number of device which thrown an error.
*
* @return int
*/
public function numberFailure();
/**
* Get the number of device which thrown an error
*
* @return int
*/
public function numberFailure();
/**
* Get all token in group that fcm cannot reach
*
* @return array
*/
public function tokensFailed();
}
/**
* Get all token in group that fcm cannot reach.
*
* @return array
*/
public function tokensFailed();
}

View File

@@ -1,142 +1,151 @@
<?php namespace LaravelFCM\Response;
<?php
namespace LaravelFCM\Response;
use Monolog\Logger;
use LaravelFCM\Message\Topics;
use Monolog\Handler\StreamHandler;
use GuzzleHttp\Psr7\Response as GuzzleResponse;
use Psr\Http\Message\ResponseInterface;
/**
* Class TopicResponse
*
* @package LaravelFCM\Response
* Class TopicResponse.
*/
class TopicResponse extends BaseResponse implements TopicResponseContract{
class TopicResponse extends BaseResponse implements TopicResponseContract
{
const LIMIT_RATE_TOPICS_EXCEEDED = 'TopicsMessageRateExceeded';
const LIMIT_RATE_TOPICS_EXCEEDED = "TopicsMessageRateExceeded";
/**
* @internal
*
* @var string
*/
protected $topic;
/**
* @internal
* @var string
*/
protected $topic;
/**
* @internal
*
* @var string
*/
protected $messageId;
/**
* @internal
* @var string
*/
protected $messageId;
/**
* @internal
*
* @var string
*/
protected $error;
/**
* @internal
* @var string
*/
protected $error;
/**
* @internal
*
* @var bool
*/
protected $needRetry = false;
/**
* @internal
* @var bool
*/
protected $needRetry = false;
/**
* TopicResponse constructor.
*
* @param \Psr\Http\Message\ResponseInterface $response
* @param Topics $topic
*/
public function __construct(ResponseInterface $response, Topics $topic)
{
$this->topic = $topic;
parent::__construct($response);
}
/**
* TopicResponse constructor.
*
* @param GuzzleResponse $response
* @param Topics $topic
*/
public function __construct(GuzzleResponse $response, Topics $topic)
{
$this->topic = $topic;
parent::__construct($response);
}
/**
* parse the response.
*
* @param $responseInJson
*/
protected function parseResponse($responseInJson)
{
if (!$this->parseSuccess($responseInJson)) {
$this->parseError($responseInJson);
}
/**
* parse the response
*
* @param $responseInJson
*/
protected function parseResponse($responseInJson)
{
if (!$this->parseSuccess($responseInJson)) {
$this->parseError($responseInJson);
}
if ($this->logEnabled) {
$this->logResponse();
}
}
$this->logResponse();
}
/**
* @internal
*
* @param $responseInJson
*/
private function parseSuccess($responseInJson)
{
if (array_key_exists(self::MESSAGE_ID, $responseInJson)) {
$this->messageId = $responseInJson[ self::MESSAGE_ID ];
}
}
/**
* @internal
* @param $responseInJson
*/
private function parseSuccess($responseInJson)
{
if (array_key_exists(self::MESSAGE_ID, $responseInJson)) {
$this->messageId = $responseInJson[ self::MESSAGE_ID ];
}
}
/**
* @internal
*
* @param $responseInJson
*/
private function parseError($responseInJson)
{
if (array_key_exists(self::ERROR, $responseInJson)) {
if (in_array(self::LIMIT_RATE_TOPICS_EXCEEDED, $responseInJson)) {
$this->needRetry = true;
}
/**
* @internal
* @param $responseInJson
*/
private function parseError($responseInJson)
{
if (array_key_exists(self::ERROR, $responseInJson)) {
if (in_array(self::LIMIT_RATE_TOPICS_EXCEEDED, $responseInJson)) {
$this->needRetry = true;
}
$this->error = $responseInJson[ self::ERROR ];
}
}
$this->error = $responseInJson[ self::ERROR ];
}
}
/**
* Log the response.
*/
protected function logResponse()
{
$logger = new Logger('Laravel-FCM');
$logger->pushHandler(new StreamHandler(storage_path('logs/laravel-fcm.log')));
/**
* Log the response
*/
protected function logResponse()
{
$logger = new Logger('Laravel-FCM');
$logger->pushHandler(new StreamHandler(storage_path('logs/laravel-fcm.log')));
$topic = $this->topic->build();
$topic = $this->topic->build();
$logMessage = "notification send to topic: $topic";
if ($this->messageId) {
$logMessage .= "with success (message-id : $this->messageId)";
}
else {
$logMessage .= "with error (error : $this->error)";
}
$logMessage = "notification send to topic: ".json_encode($topic);
if ($this->messageId) {
$logMessage .= "with success (message-id : $this->messageId)";
} else {
$logMessage .= "with error (error : $this->error)";
}
$logger->info($logMessage);
}
$logger->info($logMessage);
}
/**
* true if topic sent with success
* @return bool
*/
public function isSuccess()
{
return (bool) $this->messageId;
}
/**
* true if topic sent with success.
*
* @return bool
*/
public function isSuccess()
{
return (bool) $this->messageId;
}
/**
* return error message
* you should test if it's necessary to resent it
*
* @return string error
*/
public function error()
{
return $this->error;
}
/**
* return error message
* you should test if it's necessary to resent it.
*
* @return string error
*/
public function error()
{
return $this->error;
}
/**
* return true if it's necessary resent it using exponential backoff
*
* @return bool
*/
public function shouldRetry()
{
return $this->needRetry;
}
}
/**
* return true if it's necessary resent it using exponential backoff.
*
* @return bool
*/
public function shouldRetry()
{
return $this->needRetry;
}
}

View File

@@ -1,31 +1,31 @@
<?php namespace LaravelFCM\Response;
<?php
namespace LaravelFCM\Response;
/**
* Interface TopicResponseContract
*
* @package LaravelFCM\Response
* Interface TopicResponseContract.
*/
interface TopicResponseContract {
interface TopicResponseContract
{
/**
* true if topic sent with success.
*
* @return bool
*/
public function isSuccess();
/**
* true if topic sent with success
* @return bool
*/
public function isSuccess();
/**
* return error message
* you should test if it's necessary to resent it.
*
* @return string error
*/
public function error();
/**
* return error message
* you should test if it's necessary to resent it
*
* @return string error
*/
public function error();
/**
* return true if it's necessary resent it using exponential backoff
*
* @return bool
*/
public function shouldRetry();
}
/**
* return true if it's necessary resent it using exponential backoff.
*
* @return bool
*/
public function shouldRetry();
}

View File

@@ -1,99 +1,94 @@
<?php namespace LaravelFCM\Sender;
<?php
namespace LaravelFCM\Sender;
use LaravelFCM\Request\GroupRequest;
use GuzzleHttp\Psr7\Response as GuzzleResponse;
use Psr\Http\Message\ResponseInterface;
/**
* Class FCMGroup
*
* @package LaravelFCM\Sender
* Class FCMGroup.
*/
class FCMGroup extends HTTPSender {
const CREATE = "create";
const ADD = "add";
const REMOVE = "remove";
class FCMGroup extends HTTPSender
{
const CREATE = 'create';
const ADD = 'add';
const REMOVE = 'remove';
/**
* Create a group
*
* @param $notificationKeyName
* @param array $registrationIds
*
* @return null
*/
public function createGroup($notificationKeyName, array $registrationIds)
{
$request = new GroupRequest(self::CREATE, $notificationKeyName, null, $registrationIds);
$response = $this->client->post($this->url, $request->build());
/**
* Create a group.
*
* @param $notificationKeyName
* @param array $registrationIds
*
* @return null|string notification_key
*/
public function createGroup($notificationKeyName, array $registrationIds)
{
$request = new GroupRequest(self::CREATE, $notificationKeyName, null, $registrationIds);
return $this->getNotificationToken($response);
}
$response = $this->client->request('post', $this->url, $request->build());
/**
* add registrationId to a existing group
*
* @param $notificationKeyName
* @param $notificationKey
* @param array $registrationIds registrationIds to add
*
* @return null
*/
public function addToGroup($notificationKeyName, $notificationKey, array $registrationIds)
{
$request = new GroupRequest(self::ADD, $notificationKeyName, $notificationKey, $registrationIds);
$response = $this->client->post($this->url, $request->build());
return $this->getNotificationToken($response);
}
return $this->getNotificationToken($response);
}
/**
* add registrationId to a existing group.
*
* @param $notificationKeyName
* @param $notificationKey
* @param array $registrationIds registrationIds to add
* @return null|string notification_key
*/
public function addToGroup($notificationKeyName, $notificationKey, array $registrationIds)
{
$request = new GroupRequest(self::ADD, $notificationKeyName, $notificationKey, $registrationIds);
$response = $this->client->request('post', $this->url, $request->build());
/**
* remove registrationId to a existing group
*
* >Note: if you remove all registrationIds the group is automatically deleted
*
* @param $notificationKeyName
* @param $notificationKey
* @param array $registeredIds registrationIds to remove
*
* @return null
*/
public function removeFromGroup($notificationKeyName, $notificationKey, array $registeredIds)
{
$request = new GroupRequest(self::REMOVE, $notificationKeyName, $notificationKey, $registeredIds);
$response = $this->client->post($this->url, $request->build());
return $this->getNotificationToken($response);
}
return $this->getNotificationToken($response);
}
/**
* remove registrationId to a existing group.
*
* >Note: if you remove all registrationIds the group is automatically deleted
*
* @param $notificationKeyName
* @param $notificationKey
* @param array $registeredIds registrationIds to remove
* @return null|string notification_key
*/
public function removeFromGroup($notificationKeyName, $notificationKey, array $registeredIds)
{
$request = new GroupRequest(self::REMOVE, $notificationKeyName, $notificationKey, $registeredIds);
$response = $this->client->request('post', $this->url, $request->build());
/**
* @internal
*
* @param GuzzleResponse $response
*
* @return null
*/
private function getNotificationToken(GuzzleResponse $response)
{
if ($this->isValidResponse($response)) {
return null;
}
return $this->getNotificationToken($response);
}
$json = json_decode($response->getBody(), true);
return $json['notification_key'];
}
/**
* @internal
*
* @param \Psr\Http\Message\ResponseInterface $response
* @return null|string notification_key
*/
private function getNotificationToken(ResponseInterface $response)
{
if (! $this->isValidResponse($response)) {
return null;
}
/**
* @internal
*
* @param $response
*
* @return bool
*/
public function isValidResponse(GuzzleResponse $response)
{
return $response->getReasonPhrase() != 'OK' || $response->getStatusCode() != 200;
}
$json = json_decode($response->getBody()->getContents(), true);
}
return $json['notification_key'];
}
/**
* @param \Psr\Http\Message\ResponseInterface $response
*
* @return bool
*/
public function isValidResponse(ResponseInterface $response)
{
return $response->getStatusCode() === 200;
}
}

View File

@@ -1,4 +1,6 @@
<?php namespace LaravelFCM\Sender;
<?php
namespace LaravelFCM\Sender;
use LaravelFCM\Message\Topics;
use LaravelFCM\Request\Request;
@@ -11,113 +13,106 @@ use LaravelFCM\Response\DownstreamResponse;
use LaravelFCM\Message\PayloadNotification;
/**
* Class FCMSender
*
* @package LaravelFCM\Sender
* Class FCMSender.
*/
class FCMSender extends HTTPSender {
class FCMSender extends HTTPSender
{
const MAX_TOKEN_PER_REQUEST = 1000;
const MAX_TOKEN_PER_REQUEST = 1000;
/**
* send a downstream message to.
*
* - a unique device with is registration Token
* - or to multiples devices with an array of registrationIds
*
* @param string|array $to
* @param Options|null $options
* @param PayloadNotification|null $notification
* @param PayloadData|null $data
*
* @return DownstreamResponse|null
*/
public function sendTo($to, Options $options = null, PayloadNotification $notification = null, PayloadData $data = null)
{
$response = null;
/**
* send a downstream message to
*
* - a unique device with is registration Token
* - or to multiples devices with an array of registrationIds
*
* @param String|array $to
* @param Options|null $options
* @param PayloadNotification|null $notification
* @param PayloadData|null $data
*
* @return DownstreamResponse|null
*
*/
public function sendTo($to, Options $options = null, PayloadNotification $notification = null, PayloadData $data = null)
{
$response = null;
if (is_array($to) && !empty($to)) {
$partialTokens = array_chunk($to, self::MAX_TOKEN_PER_REQUEST, false);
foreach ($partialTokens as $tokens) {
$request = new Request($tokens, $options, $notification, $data);
if (is_array($to) && !empty($to)) {
$responseGuzzle = $this->post($request);
$partialTokens = array_chunk($to, self::MAX_TOKEN_PER_REQUEST, false);
foreach ($partialTokens as $tokens) {
$request = new Request($tokens, $options, $notification, $data);
$responsePartial = new DownstreamResponse($responseGuzzle, $tokens);
if (!$response) {
$response = $responsePartial;
} else {
$response->merge($responsePartial);
}
}
} else {
$request = new Request($to, $options, $notification, $data);
$responseGuzzle = $this->post($request);
$responseGuzzle = $this->post($request);
$response = new DownstreamResponse($responseGuzzle, $to);
}
$responsePartial = new DownstreamResponse($responseGuzzle, $tokens);
if (!$response) {
$response = $responsePartial;
}
else {
$response->merge($responsePartial);
}
}
}
else {
$request = new Request($to, $options, $notification, $data);
$responseGuzzle = $this->post($request);
return $response;
}
$response = new DownstreamResponse($responseGuzzle, $to);
}
/**
* Send a message to a group of devices identified with them notification key.
*
* @param $notificationKey
* @param Options|null $options
* @param PayloadNotification|null $notification
* @param PayloadData|null $data
*
* @return GroupResponse
*/
public function sendToGroup($notificationKey, Options $options = null, PayloadNotification $notification = null, PayloadData $data = null)
{
$request = new Request($notificationKey, $options, $notification, $data);
return $response;
}
$responseGuzzle = $this->post($request);
/**
* Send a message to a group of devices identified with them notification key
*
* @param $notificationKey
* @param Options|null $options
* @param PayloadNotification|null $notification
* @param PayloadData|null $data
*
* @return GroupResponse
*/
public function sendToGroup($notificationKey, Options $options = null, PayloadNotification $notification = null, PayloadData $data = null)
{
$request = new Request($notificationKey, $options, $notification, $data);
return new GroupResponse($responseGuzzle, $notificationKey);
}
$responseGuzzle = $this->post($request);
/**
* Send message devices registered at a or more topics.
*
* @param Topics $topics
* @param Options|null $options
* @param PayloadNotification|null $notification
* @param PayloadData|null $data
*
* @return TopicResponse
*/
public function sendToTopic(Topics $topics, Options $options = null, PayloadNotification $notification = null, PayloadData $data = null)
{
$request = new Request(null, $options, $notification, $data, $topics);
return new GroupResponse($responseGuzzle, $notificationKey);
}
$responseGuzzle = $this->post($request);
/**
* Send message devices registered at a or more topics
*
* @param Topics $topics
* @param Options|null $options
* @param PayloadNotification|null $notification
* @param PayloadData|null $data
*
* @return TopicResponse
*/
public function sendToTopic(Topics $topics, Options $options = null, PayloadNotification $notification = null, PayloadData $data = null)
{
$request = new Request(null, $options, $notification, $data, $topics);
return new TopicResponse($responseGuzzle, $topics);
}
$responseGuzzle = $this->post($request);
/**
* @internal
*
* @param \LaravelFCM\Request\Request $request
*
* @return null|\Psr\Http\Message\ResponseInterface
*/
private function post($request)
{
try {
$responseGuzzle = $this->client->request('post', $this->url, $request->build());
} catch (ClientException $e) {
$responseGuzzle = $e->getResponse();
}
return new TopicResponse($responseGuzzle, $topics);
}
/**
* @internal
*
* @param $request
*
* @return null|\Psr\Http\Message\ResponseInterface
*/
private function post($request)
{
try {
$responseGuzzle = $this->client->post($this->url, $request->build());
}
catch (ClientException $e) {
$responseGuzzle = $e->getResponse();
}
return $responseGuzzle;
}
}
return $responseGuzzle;
}
}

View File

@@ -1,38 +1,37 @@
<?php namespace LaravelFCM\Sender;
<?php
namespace LaravelFCM\Sender;
use GuzzleHttp\ClientInterface;
/**
* Class BaseSender
*
* @package LaravelFCM\Sender
* Class BaseSender.
*/
abstract class HTTPSender {
abstract class HTTPSender
{
/**
* The client used to send messages.
*
* @var \GuzzleHttp\ClientInterface
*/
protected $client;
/**
* The client used to send messages.
*
* @var GuzzleHttp\ClientInterface
*/
protected $client;
/**
* The URL entry point.
*
* @var string
*/
protected $url;
/**
* The URL entry point.
*
* @var string
*/
protected $url;
/**
* Initializes a new sender object.
*
* @param GuzzleHttp\ClientInterface $client
* @param string $url
*/
public function __construct(ClientInterface $client, $url)
{
$this->client = $client;
$this->url = $url;
}
}
/**
* Initializes a new sender object.
*
* @param \GuzzleHttp\ClientInterface $client
* @param string $url
*/
public function __construct(ClientInterface $client, $url)
{
$this->client = $client;
$this->url = $url;
}
}

View File

@@ -3,216 +3,216 @@
use GuzzleHttp\Psr7\Response;
use LaravelFCM\Response\DownstreamResponse;
class DownstreamResponseTest extends FCMTestCase {
class DownstreamResponseTest extends FCMTestCase
{
/**
* @test
*/
public function it_construct_a_response_with_a_success()
{
$token = 'new_token';
/**
* @test
*/
public function it_construct_a_response_with_a_success()
{
$token = "new_token";
$response = new Response(200, [], "{
\"multicast_id\": 108,
\"success\": 1,
\"failure\": 0,
\"canonical_ids\": 0,
\"results\": [
{ \"message_id\": \"1:08\" }
$response = new Response(200, [], '{
"multicast_id": 108,
"success": 1,
"failure": 0,
"canonical_ids": 0,
"results": [
{ "message_id": "1:08" }
]
}");
}');
$downstreamResponse = new DownstreamResponse($response, $token);
$downstreamResponse = new DownstreamResponse($response, $token);
$this->assertEquals(1, $downstreamResponse->numberSuccess());
$this->assertEquals(0, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
$this->assertEquals(1, $downstreamResponse->numberSuccess());
$this->assertEquals(0, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(0, $downstreamResponse->tokensToModify());
}
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(0, $downstreamResponse->tokensToModify());
}
/**
* @test
*/
public function it_construct_a_response_with_multiple_successes()
{
$tokens = [
"first_token",
"second_token",
"third_token"
];
/**
* @test
*/
public function it_construct_a_response_with_multiple_successes()
{
$tokens = [
'first_token',
'second_token',
'third_token',
];
$response = new Response(200, [], "{
\"multicast_id\": 108,
\"success\": 3,
\"failure\": 0,
\"canonical_ids\": 0,
\"results\": [
{ \"message_id\": \"1:01\" },
{ \"message_id\": \"1:02\" },
{ \"message_id\": \"1:03\" }
$response = new Response(200, [], '{
"multicast_id": 108,
"success": 3,
"failure": 0,
"canonical_ids": 0,
"results": [
{ "message_id": "1:01" },
{ "message_id": "1:02" },
{ "message_id": "1:03" }
]
}");
}');
$downstreamResponse = new DownstreamResponse($response, $tokens);
$downstreamResponse = new DownstreamResponse($response, $tokens);
$this->assertEquals(3, $downstreamResponse->numberSuccess());
$this->assertEquals(0, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
$this->assertEquals(3, $downstreamResponse->numberSuccess());
$this->assertEquals(0, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(0, $downstreamResponse->tokensToModify());
}
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(0, $downstreamResponse->tokensToModify());
}
/**
* @test
*/
public function it_construct_a_response_with_a_failure()
{
$token = "new_token";
/**
* @test
*/
public function it_construct_a_response_with_a_failure()
{
$token = 'new_token';
$response = new Response(200, [], "{
\"multicast_id\": 108,
\"success\": 0,
\"failure\": 1,
\"canonical_ids\": 0,
\"results\": [
{ \"error\": \"NotRegistered\" }
$response = new Response(200, [], '{
"multicast_id": 108,
"success": 0,
"failure": 1,
"canonical_ids": 0,
"results": [
{ "error": "NotRegistered" }
]
}");
}');
$downstreamResponse = new DownstreamResponse($response, $token);
$downstreamResponse = new DownstreamResponse($response, $token);
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(1, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
$this->assertFalse($downstreamResponse->hasMissingToken());
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(1, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
$this->assertFalse($downstreamResponse->hasMissingToken());
$this->assertCount(1, $downstreamResponse->tokensToDelete());
$this->assertEquals($token, $downstreamResponse->tokensToDelete()[ 0 ]);
$this->assertCount(0, $downstreamResponse->tokensToModify());
}
$this->assertCount(1, $downstreamResponse->tokensToDelete());
$this->assertEquals($token, $downstreamResponse->tokensToDelete()[ 0 ]);
$this->assertCount(0, $downstreamResponse->tokensToModify());
}
/**
* @test
*/
public function it_construct_a_response_with_multiple_failures()
{
$tokens = [
"first_token",
"second_token",
"third_token",
"fourth_token"
];
/**
* @test
*/
public function it_construct_a_response_with_multiple_failures()
{
$tokens = [
'first_token',
'second_token',
'third_token',
'fourth_token',
];
$response = new Response(200, [], "{
\"multicast_id\": 108,
\"success\": 0,
\"failure\": 3,
\"canonical_ids\": 0,
\"results\": [
{ \"error\": \"NotRegistered\" },
{ \"error\": \"InvalidRegistration\" },
{ \"error\": \"NotRegistered\" },
{ \"error\": \"MissingRegistration\"}
$response = new Response(200, [], '{
"multicast_id": 108,
"success": 0,
"failure": 3,
"canonical_ids": 0,
"results": [
{ "error": "NotRegistered" },
{ "error": "InvalidRegistration" },
{ "error": "NotRegistered" },
{ "error": "MissingRegistration"}
]
}");
}');
$downstreamResponse = new DownstreamResponse($response, $tokens);
$downstreamResponse = new DownstreamResponse($response, $tokens);
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(3, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
$this->assertTrue($downstreamResponse->hasMissingToken());
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(3, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
$this->assertTrue($downstreamResponse->hasMissingToken());
$this->assertCount(3, $downstreamResponse->tokensToDelete());
$this->assertEquals($tokens[ 0 ], $downstreamResponse->tokensToDelete()[ 0 ]);
$this->assertEquals($tokens[ 1 ], $downstreamResponse->tokensToDelete()[ 1 ]);
$this->assertEquals($tokens[ 2 ], $downstreamResponse->tokensToDelete()[ 2 ]);
$this->assertCount(0, $downstreamResponse->tokensToModify());
}
$this->assertCount(3, $downstreamResponse->tokensToDelete());
$this->assertEquals($tokens[ 0 ], $downstreamResponse->tokensToDelete()[ 0 ]);
$this->assertEquals($tokens[ 1 ], $downstreamResponse->tokensToDelete()[ 1 ]);
$this->assertEquals($tokens[ 2 ], $downstreamResponse->tokensToDelete()[ 2 ]);
$this->assertCount(0, $downstreamResponse->tokensToModify());
}
/**
* @test
*/
public function it_construct_a_response_with_a_token_to_change()
{
$token = "new_token";
/**
* @test
*/
public function it_construct_a_response_with_a_token_to_change()
{
$token = 'new_token';
$response = new Response(200, [], "{
\"multicast_id\": 108,
\"success\": 0,
\"failure\": 0,
\"canonical_ids\": 1,
\"results\": [
{ \"message_id\": \"1:2342\", \"registration_id\": \"32\" }
$response = new Response(200, [], '{
"multicast_id": 108,
"success": 0,
"failure": 0,
"canonical_ids": 1,
"results": [
{ "message_id": "1:2342", "registration_id": "32" }
]
}");
}');
$downstreamResponse = new DownstreamResponse($response, $token);
$downstreamResponse = new DownstreamResponse($response, $token);
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(0, $downstreamResponse->numberFailure());
$this->assertEquals(1, $downstreamResponse->numberModification());
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(0, $downstreamResponse->numberFailure());
$this->assertEquals(1, $downstreamResponse->numberModification());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(1, $downstreamResponse->tokensToModify());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(1, $downstreamResponse->tokensToModify());
$this->assertTrue(array_key_exists($token, $downstreamResponse->tokensToModify()));
$this->assertEquals("32", $downstreamResponse->tokensToModify()[ $token ]);
}
$this->assertTrue(array_key_exists($token, $downstreamResponse->tokensToModify()));
$this->assertEquals('32', $downstreamResponse->tokensToModify()[ $token ]);
}
/**
* @test
*/
public function it_construct_a_response_with_multiple_tokens_to_change()
{
$tokens = [
"first_token",
"second_token",
"third_token"
];
/**
* @test
*/
public function it_construct_a_response_with_multiple_tokens_to_change()
{
$tokens = [
'first_token',
'second_token',
'third_token',
];
$response = new Response(200, [], "{
\"multicast_id\": 108,
\"success\": 0,
\"failure\": 0,
\"canonical_ids\": 3,
\"results\": [
{ \"message_id\": \"1:2342\", \"registration_id\": \"32\" },
{ \"message_id\": \"1:2342\", \"registration_id\": \"33\" },
{ \"message_id\": \"1:2342\", \"registration_id\": \"34\" }
$response = new Response(200, [], '{
"multicast_id": 108,
"success": 0,
"failure": 0,
"canonical_ids": 3,
"results": [
{ "message_id": "1:2342", "registration_id": "32" },
{ "message_id": "1:2342", "registration_id": "33" },
{ "message_id": "1:2342", "registration_id": "34" }
]
}");
}');
$downstreamResponse = new DownstreamResponse($response, $tokens);
$downstreamResponse = new DownstreamResponse($response, $tokens);
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(0, $downstreamResponse->numberFailure());
$this->assertEquals(3, $downstreamResponse->numberModification());
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(0, $downstreamResponse->numberFailure());
$this->assertEquals(3, $downstreamResponse->numberModification());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(3, $downstreamResponse->tokensToModify());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(3, $downstreamResponse->tokensToModify());
$this->assertTrue(array_key_exists($tokens[ 0 ], $downstreamResponse->tokensToModify()));
$this->assertEquals("32", $downstreamResponse->tokensToModify()[ $tokens[ 0 ] ]);
$this->assertTrue(array_key_exists($tokens[ 0 ], $downstreamResponse->tokensToModify()));
$this->assertEquals('32', $downstreamResponse->tokensToModify()[ $tokens[ 0 ] ]);
$this->assertTrue(array_key_exists($tokens[ 1 ], $downstreamResponse->tokensToModify()));
$this->assertEquals("33", $downstreamResponse->tokensToModify()[ $tokens[ 1 ] ]);
$this->assertTrue(array_key_exists($tokens[ 1 ], $downstreamResponse->tokensToModify()));
$this->assertEquals('33', $downstreamResponse->tokensToModify()[ $tokens[ 1 ] ]);
$this->assertTrue(array_key_exists($tokens[ 2 ], $downstreamResponse->tokensToModify()));
$this->assertEquals("34", $downstreamResponse->tokensToModify()[ $tokens[ 2 ] ]);
}
$this->assertTrue(array_key_exists($tokens[ 2 ], $downstreamResponse->tokensToModify()));
$this->assertEquals('34', $downstreamResponse->tokensToModify()[ $tokens[ 2 ] ]);
}
/**
* @test
*/
public function it_construct_a_response_with_a_token_unavailable()
{
$token = "first_token";
/**
* @test
*/
public function it_construct_a_response_with_a_token_unavailable()
{
$token = 'first_token';
$response = new Response(200, [], '{
$response = new Response(200, [], '{
"multicast_id": 216,
"success": 0,
"failure": 1,
@@ -222,28 +222,28 @@ class DownstreamResponseTest extends FCMTestCase {
]
}');
$downstreamResponse = new DownstreamResponse($response, $token);
$downstreamResponse = new DownstreamResponse($response, $token);
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(1, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(1, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
// Unavailable is not an error caused by the token validity. it don't need to be deleted$
$this->assertCount(0, $downstreamResponse->tokensToModify());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(1, $downstreamResponse->tokensToRetry());
// Unavailable is not an error caused by the token validity. it don't need to be deleted$
$this->assertCount(0, $downstreamResponse->tokensToModify());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(1, $downstreamResponse->tokensToRetry());
$this->assertEquals($token, $downstreamResponse->tokensToRetry()[0]);
}
$this->assertEquals($token, $downstreamResponse->tokensToRetry()[0]);
}
/**
* @test
*/
public function it_construct_a_response_with_a_token_server_error()
{
$token = "first_token";
/**
* @test
*/
public function it_construct_a_response_with_a_token_server_error()
{
$token = 'first_token';
$response = new Response(200, [], '{
$response = new Response(200, [], '{
"multicast_id": 216,
"success": 0,
"failure": 1,
@@ -253,28 +253,28 @@ class DownstreamResponseTest extends FCMTestCase {
]
}');
$downstreamResponse = new DownstreamResponse($response, $token);
$downstreamResponse = new DownstreamResponse($response, $token);
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(1, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(1, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
// Unavailable is not an error caused by the token validity. it don't need to be deleted$
$this->assertCount(0, $downstreamResponse->tokensToModify());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(1, $downstreamResponse->tokensToRetry());
// Unavailable is not an error caused by the token validity. it don't need to be deleted$
$this->assertCount(0, $downstreamResponse->tokensToModify());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(1, $downstreamResponse->tokensToRetry());
$this->assertEquals($token, $downstreamResponse->tokensToRetry()[0]);
}
$this->assertEquals($token, $downstreamResponse->tokensToRetry()[0]);
}
/**
* @test
*/
public function it_construct_a_response_with_a_token_exceeded()
{
$token = "first_token";
/**
* @test
*/
public function it_construct_a_response_with_a_token_exceeded()
{
$token = 'first_token';
$response = new Response(200, [], '{
$response = new Response(200, [], '{
"multicast_id": 216,
"success": 0,
"failure": 1,
@@ -284,35 +284,35 @@ class DownstreamResponseTest extends FCMTestCase {
]
}');
$downstreamResponse = new DownstreamResponse($response, $token);
$downstreamResponse = new DownstreamResponse($response, $token);
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(1, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(1, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
// Unavailable is not an error caused by the token validity. it don't need to be deleted$
$this->assertCount(0, $downstreamResponse->tokensToModify());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(1, $downstreamResponse->tokensToRetry());
// Unavailable is not an error caused by the token validity. it don't need to be deleted$
$this->assertCount(0, $downstreamResponse->tokensToModify());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(1, $downstreamResponse->tokensToRetry());
$this->assertEquals($token, $downstreamResponse->tokensToRetry()[0]);
}
$this->assertEquals($token, $downstreamResponse->tokensToRetry()[0]);
}
/**
* @test
*/
public function it_construct_a_response_with_a_mixed_token_to_retry()
{
$tokens = [
"first_token",
"second_token",
"third_token",
"fourth_token",
"fifth_token",
"sixth_token"
];
/**
* @test
*/
public function it_construct_a_response_with_a_mixed_token_to_retry()
{
$tokens = [
'first_token',
'second_token',
'third_token',
'fourth_token',
'fifth_token',
'sixth_token',
];
$response = new Response(200, [], '{
$response = new Response(200, [], '{
"multicast_id": 216,
"success": 0,
"failure": 6,
@@ -327,41 +327,40 @@ class DownstreamResponseTest extends FCMTestCase {
]
}');
$downstreamResponse = new DownstreamResponse($response, $tokens);
$downstreamResponse = new DownstreamResponse($response, $tokens);
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(6, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
$this->assertEquals(0, $downstreamResponse->numberSuccess());
$this->assertEquals(6, $downstreamResponse->numberFailure());
$this->assertEquals(0, $downstreamResponse->numberModification());
// Unavailable is not an error caused by the token validity. it don't need to be deleted$
$this->assertCount(0, $downstreamResponse->tokensToModify());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(6, $downstreamResponse->tokensToRetry());
// Unavailable is not an error caused by the token validity. it don't need to be deleted$
$this->assertCount(0, $downstreamResponse->tokensToModify());
$this->assertCount(0, $downstreamResponse->tokensToDelete());
$this->assertCount(6, $downstreamResponse->tokensToRetry());
$this->assertEquals($tokens[ 0 ], $downstreamResponse->tokensToRetry()[ 0 ]);
$this->assertEquals($tokens[ 1 ], $downstreamResponse->tokensToRetry()[ 1 ]);
$this->assertEquals($tokens[ 2 ], $downstreamResponse->tokensToRetry()[ 2 ]);
$this->assertEquals($tokens[ 3 ], $downstreamResponse->tokensToRetry()[ 3 ]);
$this->assertEquals($tokens[ 4 ], $downstreamResponse->tokensToRetry()[ 4 ]);
$this->assertEquals($tokens[ 5 ], $downstreamResponse->tokensToRetry()[ 5 ]);
$this->assertEquals($tokens[ 0 ], $downstreamResponse->tokensToRetry()[ 0 ]);
$this->assertEquals($tokens[ 1 ], $downstreamResponse->tokensToRetry()[ 1 ]);
$this->assertEquals($tokens[ 2 ], $downstreamResponse->tokensToRetry()[ 2 ]);
$this->assertEquals($tokens[ 3 ], $downstreamResponse->tokensToRetry()[ 3 ]);
$this->assertEquals($tokens[ 4 ], $downstreamResponse->tokensToRetry()[ 4 ]);
$this->assertEquals($tokens[ 5 ], $downstreamResponse->tokensToRetry()[ 5 ]);
}
}
/**
* @test
*/
public function it_construct_a_response_with_mixed_response()
{
$tokens = [
'first_token',
'second_token',
'third_token',
'fourth_token',
'fifth_token',
'sixth_token',
];
/**
* @test
*/
public function it_construct_a_response_with_mixed_response()
{
$tokens = [
"first_token",
"second_token",
"third_token",
"fourth_token",
"fifth_token",
"sixth_token"
];
$response = new Response(200, [], '{
$response = new Response(200, [], '{
"multicast_id": 216,
"success": 3,
"failure": 3,
@@ -376,50 +375,49 @@ class DownstreamResponseTest extends FCMTestCase {
]
}');
$downstreamResponse = new DownstreamResponse($response, $tokens);
$downstreamResponse = new DownstreamResponse($response, $tokens);
$this->assertEquals(3, $downstreamResponse->numberSuccess());
$this->assertEquals(3, $downstreamResponse->numberFailure());
$this->assertEquals(1, $downstreamResponse->numberModification());
$this->assertEquals(3, $downstreamResponse->numberSuccess());
$this->assertEquals(3, $downstreamResponse->numberFailure());
$this->assertEquals(1, $downstreamResponse->numberModification());
// Unavailable is not an error caused by the token validity. it don't need to be deleted
$this->assertCount(2, $downstreamResponse->tokensToDelete());
$this->assertCount(1, $downstreamResponse->tokensToModify());
// Unavailable is not an error caused by the token validity. it don't need to be deleted
$this->assertCount(2, $downstreamResponse->tokensToDelete());
$this->assertCount(1, $downstreamResponse->tokensToModify());
$this->assertEquals($tokens[ 2 ], $downstreamResponse->tokensToDelete()[ 0 ]);
$this->assertEquals($tokens[ 5 ], $downstreamResponse->tokensToDelete()[ 1 ]);
$this->assertEquals($tokens[ 2 ], $downstreamResponse->tokensToDelete()[ 0 ]);
$this->assertEquals($tokens[ 5 ], $downstreamResponse->tokensToDelete()[ 1 ]);
$this->assertTrue(array_key_exists($tokens[ 4 ], $downstreamResponse->tokensToModify()));
$this->assertEquals("32", $downstreamResponse->tokensToModify()[ $tokens[ 4 ] ]);
}
$this->assertTrue(array_key_exists($tokens[ 4 ], $downstreamResponse->tokensToModify()));
$this->assertEquals('32', $downstreamResponse->tokensToModify()[ $tokens[ 4 ] ]);
}
/**
* @test
*/
public function it_construct_a_response_with_multiples_response()
{
/**
* @test
*/
public function it_construct_a_response_with_multiples_response()
{
$tokens = [
'first_token',
'second_token',
'third_token',
'fourth_token',
'fifth_token',
'sixth_token',
'seventh_token',
];
$tokens = [
"first_token",
"second_token",
"third_token",
"fourth_token",
"fifth_token",
"sixth_token",
"seventh_token"
];
$tokens1 = [
'first_1_token',
'second_1_token',
'third_1_token',
'fourth_1_token',
'fifth_1_token',
'sixth_1_token',
'seventh_1_token',
];
$tokens1 = [
"first_1_token",
"second_1_token",
"third_1_token",
"fourth_1_token",
"fifth_1_token",
"sixth_1_token",
"seventh_1_token"
];
$response = new Response(200, [], '{
$response = new Response(200, [], '{
"multicast_id": 216,
"success": 3,
"failure": 3,
@@ -435,28 +433,28 @@ class DownstreamResponseTest extends FCMTestCase {
]
}');
$downstreamResponse = new DownstreamResponse($response, $tokens);
$downstreamResponse1 = new DownstreamResponse($response, $tokens1);
$downstreamResponse = new DownstreamResponse($response, $tokens);
$downstreamResponse1 = new DownstreamResponse($response, $tokens1);
$downstreamResponse->merge($downstreamResponse1);
$downstreamResponse->merge($downstreamResponse1);
$this->assertEquals(6, $downstreamResponse->numberSuccess());
$this->assertEquals(6, $downstreamResponse->numberFailure());
$this->assertEquals(2, $downstreamResponse->numberModification());
$this->assertEquals(6, $downstreamResponse->numberSuccess());
$this->assertEquals(6, $downstreamResponse->numberFailure());
$this->assertEquals(2, $downstreamResponse->numberModification());
// Unavailable is not an error caused by the token validity. it don't need to be deleted
$this->assertCount(4, $downstreamResponse->tokensToDelete());
$this->assertCount(2, $downstreamResponse->tokensToModify());
$this->assertCount(2, $downstreamResponse->tokensWithError());
// Unavailable is not an error caused by the token validity. it don't need to be deleted
$this->assertCount(4, $downstreamResponse->tokensToDelete());
$this->assertCount(2, $downstreamResponse->tokensToModify());
$this->assertCount(2, $downstreamResponse->tokensWithError());
$this->assertEquals($tokens[ 2 ], $downstreamResponse->tokensToDelete()[ 0 ]);
$this->assertEquals($tokens1[ 2 ], $downstreamResponse->tokensToDelete()[ 2 ]);
$this->assertEquals($tokens[ 5 ], $downstreamResponse->tokensToDelete()[ 1 ]);
$this->assertEquals($tokens1[ 5 ], $downstreamResponse->tokensToDelete()[ 3 ]);
$this->assertEquals($tokens[ 2 ], $downstreamResponse->tokensToDelete()[ 0 ]);
$this->assertEquals($tokens1[ 2 ], $downstreamResponse->tokensToDelete()[ 2 ]);
$this->assertEquals($tokens[ 5 ], $downstreamResponse->tokensToDelete()[ 1 ]);
$this->assertEquals($tokens1[ 5 ], $downstreamResponse->tokensToDelete()[ 3 ]);
$this->assertCount(2, $downstreamResponse->tokensToRetry());
$this->assertCount(2, $downstreamResponse->tokensToRetry());
$this->assertEquals("MessageTooBig", $downstreamResponse->tokensWithError()[$tokens[6]]);
$this->assertEquals("MessageTooBig", $downstreamResponse->tokensWithError()[$tokens1[6]]);
}
}
$this->assertEquals('MessageTooBig', $downstreamResponse->tokensWithError()[$tokens[6]]);
$this->assertEquals('MessageTooBig', $downstreamResponse->tokensWithError()[$tokens1[6]]);
}
}

View File

@@ -4,14 +4,14 @@ use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Response;
use LaravelFCM\Sender\FCMSender;
class ResponseTest extends FCMTestCase {
/**
* @test
*/
public function it_send_a_notification_to_a_device()
{
$response = new Response(200, [], '{
class ResponseTest extends FCMTestCase
{
/**
* @test
*/
public function it_send_a_notification_to_a_device()
{
$response = new Response(200, [], '{
"multicast_id": 216,
"success": 3,
"failure": 3,
@@ -19,24 +19,23 @@ class ResponseTest extends FCMTestCase {
"results": [
{ "message_id": "1:0408" }
]
}' );
}');
$client = Mockery::mock(Client::class);
$client->shouldReceive('post')->once()->andReturn($response);
$client = Mockery::mock(Client::class);
$client->shouldReceive('request')->once()->andReturn($response);
$tokens = 'uniqueToken';
$tokens = 'uniqueToken';
$fcm = new FCMSender($client, 'http://test.test');
$fcm->sendTo($tokens);
}
$fcm = new FCMSender($client, 'http://test.test');
$fcm->sendTo($tokens);
}
/**
* @test
*/
public function it_send_a_notification_to_more_than_1000_devices()
{
$response = new Response(200, [], '{
/**
* @test
*/
public function it_send_a_notification_to_more_than_1000_devices()
{
$response = new Response(200, [], '{
"multicast_id": 216,
"success": 3,
"failure": 3,
@@ -49,26 +48,26 @@ class ResponseTest extends FCMTestCase {
{ "message_id": "1:2342", "registration_id": "32" },
{ "error": "NotRegistered"}
]
}' );
}');
$client = Mockery::mock(Client::class);
$client->shouldReceive('post')->times(10)->andReturn($response);
$client = Mockery::mock(Client::class);
$client->shouldReceive('request')->times(10)->andReturn($response);
$tokens = [];
for ($i=0 ; $i<10000 ; $i++) {
$tokens[$i] = 'token_'.$i;
}
$tokens = [];
for ($i = 0; $i < 10000; ++$i) {
$tokens[$i] = 'token_'.$i;
}
$fcm = new FCMSender($client, 'http://test.test');
$fcm->sendTo($tokens);
}
$fcm = new FCMSender($client, 'http://test.test');
$fcm->sendTo($tokens);
}
/**
* @test
*/
public function an_empty_array_of_tokens_thrown_an_exception()
{
$response = new Response(400, [], '{
/**
* @test
*/
public function an_empty_array_of_tokens_thrown_an_exception()
{
$response = new Response(400, [], '{
"multicast_id": 216,
"success": 3,
"failure": 3,
@@ -81,13 +80,13 @@ class ResponseTest extends FCMTestCase {
{ "message_id": "1:2342", "registration_id": "32" },
{ "error": "NotRegistered"}
]
}' );
}');
$client = Mockery::mock(Client::class);
$client->shouldReceive('post')->once()->andReturn($response);
$client = Mockery::mock(Client::class);
$client->shouldReceive('request')->once()->andReturn($response);
$fcm = new FCMSender($client, 'http://test.test');
$this->setExpectedException(\LaravelFCM\Response\Exceptions\InvalidRequestException::class);
$fcm->sendTo([]);
}
}
$fcm = new FCMSender($client, 'http://test.test');
$this->setExpectedException(\LaravelFCM\Response\Exceptions\InvalidRequestException::class);
$fcm->sendTo([]);
}
}

View File

@@ -2,22 +2,21 @@
use Illuminate\Foundation\Testing\TestCase;
abstract class FCMTestCase extends TestCase {
abstract class FCMTestCase extends TestCase
{
public function createApplication()
{
$app = require __DIR__.'/../vendor/laravel/laravel/bootstrap/app.php';
public function createApplication()
{
$app = require __DIR__.'/../vendor/laravel/laravel/bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
$app->register(LaravelFCM\FCMServiceProvider::class);
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
$app->register(LaravelFCM\FCMServiceProvider::class);
$app['config']['fcm.driver'] = 'http';
$app['config']['fcm.http.timeout'] = 20;
$app['config']['fcm.http.server_send_url'] = 'http://test.test';
$app['config']['fcm.http.server_key'] = 'key=myKey';
$app['config']['fcm.http.sender_id'] = 'SENDER_ID';
$app['config']['fcm.driver'] = 'http';
$app['config']['fcm.http.timeout'] = 20;
$app['config']['fcm.http.server_send_url'] = 'http://test.test';
$app['config']['fcm.http.server_key'] = 'key=myKey';
$app['config']['fcm.http.sender_id'] = 'SENDER_ID';
return $app;
}
}
return $app;
}
}

View File

@@ -2,35 +2,35 @@
use LaravelFCM\Response\GroupResponse;
class GroupResponseTest extends FCMTestCase {
class GroupResponseTest extends FCMTestCase
{
/**
* @test
*/
public function it_construct_a_response_with_successes()
{
$notificationKey = 'notificationKey';
/**
* @test
*/
public function it_construct_a_response_with_successes()
{
$notificationKey = "notificationKey";
$response = new \GuzzleHttp\Psr7\Response(200, [], '{
$response = new \GuzzleHttp\Psr7\Response(200, [], '{
"success": 2,
"failure": 0
}');
$responseGroup = new GroupResponse($response, $notificationKey);
$responseGroup = new GroupResponse($response, $notificationKey);
$this->assertEquals(2, $responseGroup->numberSuccess());
$this->assertEquals(0, $responseGroup->numberFailure());
$this->assertCount(0, $responseGroup->tokensFailed());
}
$this->assertEquals(2, $responseGroup->numberSuccess());
$this->assertEquals(0, $responseGroup->numberFailure());
$this->assertCount(0, $responseGroup->tokensFailed());
}
/**
* @test
*/
public function it_construct_a_response_with_failures()
{
$notificationKey = "notificationKey";
/**
* @test
*/
public function it_construct_a_response_with_failures()
{
$notificationKey = 'notificationKey';
$response = new \GuzzleHttp\Psr7\Response(200, [], '{
$response = new \GuzzleHttp\Psr7\Response(200, [], '{
"success": 0,
"failure": 2,
"failed_registration_ids":[
@@ -38,24 +38,24 @@ class GroupResponseTest extends FCMTestCase {
"regId2"
]}');
$responseGroup = new GroupResponse($response, $notificationKey);
$responseGroup = new GroupResponse($response, $notificationKey);
$this->assertEquals(0, $responseGroup->numberSuccess());
$this->assertEquals(2, $responseGroup->numberFailure());
$this->assertCount(2, $responseGroup->tokensFailed());
$this->assertEquals(0, $responseGroup->numberSuccess());
$this->assertEquals(2, $responseGroup->numberFailure());
$this->assertCount(2, $responseGroup->tokensFailed());
$this->assertEquals("regId1", $responseGroup->tokensFailed()[ 0]);
$this->assertEquals("regId2", $responseGroup->tokensFailed()[ 1]);
}
$this->assertEquals('regId1', $responseGroup->tokensFailed()[ 0]);
$this->assertEquals('regId2', $responseGroup->tokensFailed()[ 1]);
}
/**
* @test
*/
public function it_construct_a_response_with_partials_failures()
{
$notificationKey = "notificationKey";
/**
* @test
*/
public function it_construct_a_response_with_partials_failures()
{
$notificationKey = 'notificationKey';
$response = new \GuzzleHttp\Psr7\Response(200, [], '{
$response = new \GuzzleHttp\Psr7\Response(200, [], '{
"success": 1,
"failure": 2,
"failed_registration_ids":[
@@ -63,10 +63,10 @@ class GroupResponseTest extends FCMTestCase {
"regId2"
]}');
$responseGroup = new GroupResponse($response, $notificationKey);
$responseGroup = new GroupResponse($response, $notificationKey);
$this->assertEquals(1, $responseGroup->numberSuccess());
$this->assertEquals(2, $responseGroup->numberFailure());
$this->assertCount(2, $responseGroup->tokensFailed());
}
}
$this->assertEquals(1, $responseGroup->numberSuccess());
$this->assertEquals(2, $responseGroup->numberFailure());
$this->assertCount(2, $responseGroup->tokensFailed());
}
}

View File

@@ -5,19 +5,19 @@ use LaravelFCM\Message\OptionsPriorities;
use LaravelFCM\Message\PayloadDataBuilder;
use LaravelFCM\Message\PayloadNotificationBuilder;
class PayloadTest extends FCMTestCase {
/**
* @test
*/
public function it_construct_a_valid_json_with_option()
{
$targetPartial = '{
class PayloadTest extends FCMTestCase
{
/**
* @test
*/
public function it_construct_a_valid_json_with_option()
{
$targetPartial = '{
"collapse_key":"collapseKey",
"content_available":true
}';
$targetFull = '{
$targetFull = '{
"collapse_key":"collapseKey",
"content_available":true,
"priority":"high",
@@ -27,70 +27,70 @@ class PayloadTest extends FCMTestCase {
"dry_run": true
}';
$optionBuilder = new OptionsBuilder();
$optionBuilder = new OptionsBuilder();
$optionBuilder->setCollapseKey("collapseKey");
$optionBuilder->setContentAvailable(true);
$optionBuilder->setCollapseKey('collapseKey');
$optionBuilder->setContentAvailable(true);
$json = json_encode($optionBuilder->build()->toArray());
$this->assertJsonStringEqualsJsonString($targetPartial, $json);
$optionBuilder->setPriority(OptionsPriorities::high)
->setDelayWhileIdle(true)
->setDryRun(true)
->setRestrictedPackageName("customPackageName")
->setTimeToLive(200);
$json = json_encode($optionBuilder->build()->toArray());
$this->assertJsonStringEqualsJsonString($targetPartial, $json);
$json = json_encode($optionBuilder->build()->toArray());
$this->assertJsonStringEqualsJsonString($targetFull, $json);
$optionBuilder->setPriority(OptionsPriorities::high)
->setDelayWhileIdle(true)
->setDryRun(true)
->setRestrictedPackageName('customPackageName')
->setTimeToLive(200);
}
$json = json_encode($optionBuilder->build()->toArray());
$this->assertJsonStringEqualsJsonString($targetFull, $json);
}
/**
* @test
*/
public function it_construct_a_valid_json_with_data()
{
$targetAdd = '{
/**
* @test
*/
public function it_construct_a_valid_json_with_data()
{
$targetAdd = '{
"first_data":"first",
"second_data":true
}';
$targetSet = '
$targetSet = '
{
"third_data":"third",
"fourth_data":4
}';
$dataBuilder = new PayloadDataBuilder();
$dataBuilder = new PayloadDataBuilder();
$dataBuilder->addData([ 'first_data' => 'first' ])
->addData([ 'second_data' => true ]);
$dataBuilder->addData(['first_data' => 'first'])
->addData(['second_data' => true]);
$json = json_encode($dataBuilder->build()->toArray());
$this->assertJsonStringEqualsJsonString($targetAdd, $json);
$json = json_encode($dataBuilder->build()->toArray());
$this->assertJsonStringEqualsJsonString($targetAdd, $json);
$dataBuilder->setData([ 'third_data' => 'third', 'fourth_data' => 4 ]);
$dataBuilder->setData(['third_data' => 'third', 'fourth_data' => 4]);
$json = json_encode($dataBuilder->build()->toArray());
$this->assertJsonStringEqualsJsonString($targetSet, $json);
}
$json = json_encode($dataBuilder->build()->toArray());
$this->assertJsonStringEqualsJsonString($targetSet, $json);
}
/**
* @test
*/
public function it_construct_a_valid_json_with_notification()
{
$targetPartial = '{
/**
* @test
*/
public function it_construct_a_valid_json_with_notification()
{
$targetPartial = '{
"title":"test_title",
"body":"test_body",
"badge":"test_badge",
"sound":"test_sound"
}';
$targetFull = '{
$targetFull = '{
"title":"test_title",
"body":"test_body",
"android_channel_id":"test_channel_id",
"badge":"test_badge",
"sound":"test_sound",
"tag":"test_tag",
@@ -103,27 +103,28 @@ class PayloadTest extends FCMTestCase {
"icon":"test_icon"
}';
$notificationBuilder = new PayloadNotificationBuilder();
$notificationBuilder = new PayloadNotificationBuilder();
$notificationBuilder->setTitle('test_title')
->setBody('test_body')
->setSound('test_sound')
->setBadge('test_badge');
$notificationBuilder->setTitle('test_title')
->setBody('test_body')
->setSound('test_sound')
->setBadge('test_badge');
$json = json_encode($notificationBuilder->build()->toArray());
$this->assertJsonStringEqualsJsonString($targetPartial, $json);
$json = json_encode($notificationBuilder->build()->toArray());
$this->assertJsonStringEqualsJsonString($targetPartial, $json);
$notificationBuilder->setTag('test_tag')
->setColor('test_color')
->setClickAction('test_click_action')
->setBodyLocationKey('test_body_key')
->setBodyLocationArgs('[ body0, body1 ]')
->setTitleLocationKey('test_title_key')
->setTitleLocationArgs('[ title0, title1 ]')
->setIcon('test_icon');
$notificationBuilder
->setChannelId('test_channel_id')
->setTag('test_tag')
->setColor('test_color')
->setClickAction('test_click_action')
->setBodyLocationKey('test_body_key')
->setBodyLocationArgs('[ body0, body1 ]')
->setTitleLocationKey('test_title_key')
->setTitleLocationArgs('[ title0, title1 ]')
->setIcon('test_icon');
$json = json_encode($notificationBuilder->build()->toArray());
$this->assertJsonStringEqualsJsonString($targetFull, $json);
}
}
$json = json_encode($notificationBuilder->build()->toArray());
$this->assertJsonStringEqualsJsonString($targetFull, $json);
}
}

View File

@@ -3,63 +3,62 @@
use GuzzleHttp\Psr7\Response;
use LaravelFCM\Response\TopicResponse;
class TopicsResponseTest extends FCMTestCase {
class TopicsResponseTest extends FCMTestCase
{
/**
* @test
*/
public function it_construct_a_topic_response_with_success()
{
$topic = new \LaravelFCM\Message\Topics();
$topic->topic('topicName');
/**
* @test
*/
public function it_construct_a_topic_response_with_success()
{
$topic = new \LaravelFCM\Message\Topics();
$topic->topic('topicName');
$response = new Response(200, [], '{
$response = new Response(200, [], '{
"message_id": "1234"
}');
$topicResponse = new TopicResponse($response, $topic);
$topicResponse = new TopicResponse($response, $topic);
$this->assertTrue($topicResponse->isSuccess());
$this->assertFalse($topicResponse->shouldRetry());
$this->assertNull($topicResponse->error());
}
$this->assertTrue($topicResponse->isSuccess());
$this->assertFalse($topicResponse->shouldRetry());
$this->assertNull($topicResponse->error());
}
/**
* @test
*/
public function it_construct_a_topic_response_with_error()
{
$topic = new \LaravelFCM\Message\Topics();
$topic->topic('topicName');
/**
* @test
*/
public function it_construct_a_topic_response_with_error()
{
$topic = new \LaravelFCM\Message\Topics();
$topic->topic('topicName');
$response = new Response(200, [], '{
$response = new Response(200, [], '{
"error": "MessageTooBig"
}');
$topicResponse = new TopicResponse($response, $topic);
$topicResponse = new TopicResponse($response, $topic);
$this->assertFalse($topicResponse->isSuccess());
$this->assertFalse($topicResponse->shouldRetry());
$this->assertEquals("MessageTooBig", $topicResponse->error());
}
$this->assertFalse($topicResponse->isSuccess());
$this->assertFalse($topicResponse->shouldRetry());
$this->assertEquals('MessageTooBig', $topicResponse->error());
}
/**
* @test
*/
public function it_construct_a_topic_response_with_error_and_it_should_retry()
{
$topic = new \LaravelFCM\Message\Topics();
$topic->topic('topicName');
/**
* @test
*/
public function it_construct_a_topic_response_with_error_and_it_should_retry()
{
$topic = new \LaravelFCM\Message\Topics();
$topic->topic('topicName');
$response = new Response(200, [], '{
$response = new Response(200, [], '{
"error": "TopicsMessageRateExceeded"
}');
$topicResponse = new TopicResponse($response, $topic);
$topicResponse = new TopicResponse($response, $topic);
$this->assertFalse($topicResponse->isSuccess());
$this->assertTrue($topicResponse->shouldRetry());
$this->assertEquals("TopicsMessageRateExceeded", $topicResponse->error());
}
}
$this->assertFalse($topicResponse->isSuccess());
$this->assertTrue($topicResponse->shouldRetry());
$this->assertEquals('TopicsMessageRateExceeded', $topicResponse->error());
}
}

View File

@@ -6,145 +6,144 @@ use LaravelFCM\Message\Topics;
use LaravelFCM\Sender\FCMSender;
use LaravelFCM\Message\Exceptions\NoTopicProvidedException;
class TopicsTest extends FCMTestCase {
class TopicsTest extends FCMTestCase
{
/**
* @test
*/
public function it_throw_an_exception_if_no_topic_is_provided()
{
$topics = new Topics();
/**
* @test
*/
public function it_throw_an_exception_if_no_topic_is_provided()
{
$topics = new Topics();
$this->setExpectedException(NoTopicProvidedException::class);
$topics->build();
}
$this->setExpectedException(NoTopicProvidedException::class);
$topics->build();
}
/**
* @test
*/
public function it_has_only_one_topic()
{
$target = '/topics/myTopic';
/**
* @test
*/
public function it_has_only_one_topic()
{
$target = "/topics/myTopic";
$topics = new Topics();
$topics = new Topics();
$topics->topic('myTopic');
$topics->topic('myTopic');
$this->assertEquals($target, $topics->build());
}
$this->assertEquals($target, $topics->build());
}
/**
* @test
*/
public function it_has_two_topics_and()
{
$target = [
'condition' => "'firstTopic' in topics && 'secondTopic' in topics",
];
/**
* @test
*/
public function it_has_two_topics_and()
{
$target = [
'condition' => "'firstTopic' in topics && 'secondTopic' in topics"
];
$topics = new Topics();
$topics = new Topics();
$topics->topic('firstTopic')->andTopic('secondTopic');
$topics->topic('firstTopic')->andTopic('secondTopic');
$this->assertEquals($target, $topics->build());
}
$this->assertEquals($target, $topics->build());
}
/**
* @test
*/
public function it_has_two_topics_or()
{
$target = [
'condition' => "'firstTopic' in topics || 'secondTopic' in topics",
];
/**
* @test
*/
public function it_has_two_topics_or()
{
$target = [
'condition' => "'firstTopic' in topics || 'secondTopic' in topics"
];
$topics = new Topics();
$topics = new Topics();
$topics->topic('firstTopic')->orTopic('secondTopic');
$topics->topic('firstTopic')->orTopic('secondTopic');
$this->assertEquals($target, $topics->build());
}
$this->assertEquals($target, $topics->build());
}
/**
* @test
*/
public function it_has_two_topics_or_and_one_and()
{
$target = [
'condition' => "'firstTopic' in topics || 'secondTopic' in topics && 'thirdTopic' in topics",
];
/**
* @test
*/
public function it_has_two_topics_or_and_one_and()
{
$target = [
'condition' => "'firstTopic' in topics || 'secondTopic' in topics && 'thirdTopic' in topics"
];
$topics = new Topics();
$topics = new Topics();
$topics->topic('firstTopic')->orTopic('secondTopic')->andTopic('thirdTopic');
$topics->topic('firstTopic')->orTopic('secondTopic')->andTopic('thirdTopic');
$this->assertEquals($target, $topics->build());
}
$this->assertEquals($target, $topics->build());
}
/**
* @test
*/
public function it_has_a_complex_topic_condition()
{
$target = [
'condition' => "'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics) || ('TopicD' in topics && 'TopicE' in topics)",
];
/**
* @test
*/
public function it_has_a_complex_topic_condition()
{
$target = [
'condition' => "'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics) || ('TopicD' in topics && 'TopicE' in topics)"
];
$topics = new Topics();
$topics = new Topics();
$topics->topic('TopicA')
->andTopic(function ($condition) {
$condition->topic('TopicB')->orTopic('TopicC');
})
->orTopic(function ($condition) {
$condition->topic('TopicD')->andTopic('TopicE');
});
$topics->topic('TopicA')
->andTopic(function($condition) {
$condition->topic('TopicB')->orTopic('TopicC');
})
->orTopic(function($condition) {
$condition->topic('TopicD')->andTopic('TopicE');
});
$this->assertEquals($target, $topics->build());
}
/**
* @test
*/
public function it_send_a_notification_to_a_topic()
{
$response = new Response(200, [], '{"message_id":6177433633397011933}');
$this->assertEquals($target, $topics->build());
}
$client = Mockery::mock(Client::class);
$client->shouldReceive('request')->once()->andReturn($response);
/**
* @test
*/
public function it_send_a_notification_to_a_topic()
{
$response = new Response(200, [], '{"message_id":6177433633397011933}' );
$fcm = new FCMSender($client, 'http://test.test');
$client = Mockery::mock(Client::class);
$client->shouldReceive('post')->once()->andReturn($response);
$topics = new Topics();
$topics->topic('test');
$fcm = new FCMSender($client, 'http://test.test');
$response = $fcm->sendToTopic($topics);
$topics = new Topics();
$topics->topic('test');
$this->assertTrue($response->isSuccess());
$this->assertFalse($response->shouldRetry());
$this->assertNull($response->error());
}
$response = $fcm->sendToTopic($topics);
/**
* @test
*/
public function it_send_a_notification_to_a_topic_and_return_error()
{
$response = new Response(200, [], '{"error":"TopicsMessageRateExceeded"}');
$this->assertTrue($response->isSuccess());
$this->assertFalse($response->shouldRetry());
$this->assertNull($response->error());
}
$client = Mockery::mock(Client::class);
$client->shouldReceive('request')->once()->andReturn($response);
/**
* @test
*/
public function it_send_a_notification_to_a_topic_and_return_error()
{
$response = new Response(200, [], '{"error":"TopicsMessageRateExceeded"}' );
$fcm = new FCMSender($client, 'http://test.test');
$client = Mockery::mock(Client::class);
$client->shouldReceive('post')->once()->andReturn($response);
$topics = new Topics();
$topics->topic('test');
$fcm = new FCMSender($client, 'http://test.test');
$response = $fcm->sendToTopic($topics);
$topics = new Topics();
$topics->topic('test');
$response = $fcm->sendToTopic($topics);
$this->assertFalse($response->isSuccess());
$this->assertTrue($response->shouldRetry());
$this->assertEquals('TopicsMessageRateExceeded', $response->error());
}
}
$this->assertFalse($response->isSuccess());
$this->assertTrue($response->shouldRetry());
$this->assertEquals('TopicsMessageRateExceeded', $response->error());
}
}

View File

@@ -1,223 +1,232 @@
<?php namespace LaravelFCM\Mocks;
<?php
namespace LaravelFCM\Mocks;
use LaravelFCM\Response\DownstreamResponse;
use LaravelFCM\Response\DownstreamResponseContract;
/**
* Class MockDownstreamResponse **Only use it for testing**
*
* @package LaravelFCM\Response
* Class MockDownstreamResponse **Only use it for testing**.
*/
class MockDownstreamResponse implements DownstreamResponseContract {
class MockDownstreamResponse implements DownstreamResponseContract
{
/**
* @internal
*
* @var int
*/
protected $numberTokensSuccess = 0;
/**
* @internal
*
* @var
*/
protected $messageId;
/**
* @internal
*
* @var int
*/
protected $numberTokensSuccess = 0;
/**
* @internal
*
* @var array
*/
protected $tokensToDelete = [];
/**
* @internal
*
* @var array
*/
protected $tokensToModify = [];
/**
* @internal
*
* @var array
*/
protected $tokensToRetry = [];
/**
* @internal
*
* @var
*/
protected $messageId;
/**
* @internal
*
* @var array
*/
protected $tokensWithError = [];
/**
* @internal
*
* @var array
*/
protected $tokensToDelete = [];
/**
* @internal
*
* @var bool
*/
protected $hasMissingToken = false;
/**
* @internal
*
* @var array
*/
/**
* DownstreamResponse constructor.
*
* @param $numberSuccess
*/
public function __construct($numberSuccess)
{
$this->numberTokensSuccess = $numberSuccess;
}
protected $tokensToModify = [];
/**
* @internal
*
* @var array
*/
/**
* Not using it.
*
* @param DownstreamResponse $response
*
* @throws \Exception
*/
public function merge(DownstreamResponse $response)
{
throw new \Exception('You cannot use this method for mocking response');
}
protected $tokensToRetry = [];
/**
* Get the number of device reached with success + numberTokenToModify.
*
* @return int
*/
public function numberSuccess()
{
return $this->numberTokensSuccess + count($this->tokensToModify);
}
/**
* @internal
*
* @var array
*/
protected $tokensWithError = [];
/**
* Get the number of device which thrown an error.
*
* @return int
*/
public function numberFailure()
{
return count($this->tokensToDelete()) + count($this->tokensWithError);
}
/**
* @internal
* @var bool
*/
protected $hasMissingToken = false;
/**
* Get the number of device that you need to modify their token.
*
* @return int
*/
public function numberModification()
{
return count($this->tokensToModify());
}
/**
* DownstreamResponse constructor.
*
* @param $numberSuccess
*/
public function __construct($numberSuccess)
{
$this->numberTokensSuccess = $numberSuccess;
}
/**
* Add a token to delete.
*
* @param $token
* @return MockDownstreamResponse
*/
public function addTokenToDelete($token)
{
$this->tokensToDelete[] = $token;
return $this;
}
/**
* Not using it
*
* @param DownstreamResponse $response
*
* @throws \Exception
*/
public function merge(DownstreamResponse $response)
{
throw new \Exception('You cannot use this method for mocking response');
}
/**
* get token to delete
* remove all tokens returned by this method in your database.
*
* @return array
*/
public function tokensToDelete()
{
return $this->tokensToDelete;
}
/**
* Get the number of device reached with success + numberTokenToModify
*
* @return int
*/
public function numberSuccess()
{
return $this->numberTokensSuccess + count($this->tokensToModify);
}
/**
* Add a token to modify.
*
* @param $oldToken
* @param $newToken
* @return MockDownstreamResponse
*/
public function addTokenToModify($oldToken, $newToken)
{
$this->tokensToModify[$oldToken] = $newToken;
return $this;
}
/**
* Get the number of device which thrown an error
*
* @return int
*/public function numberFailure()
{
return count($this->tokensToDelete()) + count($this->tokensWithError);
}
/**
* get token to modify
* key: oldToken
* value: new token
* find the old token in your database and replace it with the new one.
*
* @return array
*/
public function tokensToModify()
{
return $this->tokensToModify;
}
/**
* Get the number of device that you need to modify their token
*
* @return int
*/
public function numberModification()
{
return count($this->tokensToModify());
}
/**
* Add a token to retry.
*
* @param $token
* @return MockDownstreamResponse
*/
public function addTokenToRetry($token)
{
$this->tokensToRetry[] = $token;
return $this;
}
/**
* Add a token to delete
*
* @param $token
*/
public function addTokenToDelete($token)
{
$this->tokensToDelete[] = $token;
}
/**
* Get tokens that you should resend using exponential backoof.
*
* @return array
*/
public function tokensToRetry()
{
return $this->tokensToRetry;
}
/**
* get token to delete
* remove all tokens returned by this method in your database
*
* @return array
*/
public function tokensToDelete()
{
return $this->tokensToDelete;
}
/**
* Add a token to errors.
*
* @param $token
* @param $message
* @return MockDownstreamResponse
*/
public function addTokenWithError($token, $message)
{
$this->tokensWithError[$token] = $message;
return $this;
}
/**
* Add a token to modify
*
* @param $oldToken
* @param $newToken
*/
public function addTokenToModify($oldToken, $newToken)
{
$this->tokensToModify[$oldToken] = $newToken;
}
/**
* Get tokens that thrown an error
* key : token
* value : error
* In production, remove these tokens from you database.
*
* @return array
*/
public function tokensWithError()
{
return $this->tokensWithError;
}
/**
* get token to modify
* key: oldToken
* value: new token
* find the old token in your database and replace it with the new one
*
* @return array
*/
public function tokensToModify()
{
return $this->tokensToModify;
}
/**
* change missing token state.
*
* @param $hasMissingToken
* @return MockDownstreamResponse
*/
public function setMissingToken($hasMissingToken)
{
$this->hasMissingToken = $hasMissingToken;
return $this;
}
/**
* Add a token to retry
*
* @param $token
*/
public function addTokenToRetry($token)
{
$this->tokensToRetry[] = $token;
}
/**
* Get tokens that you should resend using exponential backoof
*
* @return array
*/
public function tokensToRetry()
{
return $this->tokensToRetry;
}
/**
* Add a token to errors
*
* @param $token
* @param $message
*/
public function addTokenWithError($token, $message)
{
$this->tokensWithError[$token] = $message;
}
/**
* Get tokens that thrown an error
* key : token
* value : error
* In production, remove these tokens from you database
*
* @return array
*/
public function tokensWithError()
{
return $this->tokensWithError;
}
/**
* change missing token state
* @param $hasMissingToken
*/
public function setMissingToken($hasMissingToken)
{
$this->hasMissingToken = $hasMissingToken;
}
/**
* check if missing tokens was given to the request
* If true, remove all the empty token in your database
*
* @return bool
*/
public function hasMissingToken()
{
return $this->hasMissingToken;
}
}
/**
* check if missing tokens was given to the request
* If true, remove all the empty token in your database.
*
* @return bool
*/
public function hasMissingToken()
{
return $this->hasMissingToken;
}
}

View File

@@ -1,88 +1,123 @@
<?php namespace LaravelFCM\Mocks;
<?php
namespace LaravelFCM\Mocks;
use LaravelFCM\Response\GroupResponseContract;
/**
* Class MockGroupResponse **Only use it for testing**
*
* @package LaravelFCM\Response
* Class MockGroupResponse **Only use it for testing**.
*/
class MockGroupResponse implements GroupResponseContract {
class MockGroupResponse implements GroupResponseContract
{
/**
* @internal
*
* @var int
*/
protected $numberTokensSuccess = 0;
/**
* @internal
* @var int
*/
protected $numberTokensSuccess = 0;
/**
* @internal
*
* @var int
*/
protected $numberTokensFailure = 0;
/**
* @internal
* @var int
*/
protected $numberTokensFailure = 0;
/**
* @internal
*
* @var array
*/
protected $tokensFailed = [];
/**
* @internal
* @var array
*/
protected $tokensFailed = [];
/**
* @internal
*
* @var string
*/
protected $to;
/**
* set number of success
* @param $numberSuccess
*/
public function setNumberSuccess($numberSuccess)
{
$this->numberTokensSuccess = $numberSuccess;
}
/**
* set number of success.
*
* @param int $numberSuccess
* @return MockGroupResponse
*/
public function setNumberSuccess($numberSuccess)
{
$this->numberTokensSuccess = $numberSuccess;
return $this;
}
/**
* Get the number of device reached with success
*
* @return int
*/
public function numberSuccess()
{
return $this->numberTokensSuccess;
}
/**
* Get the number of device reached with success.
*
* @return int
*/
public function numberSuccess()
{
return $this->numberTokensSuccess;
}
/**
* set number of failures
*
* @param $numberFailures
*/
public function setNumberFailure($numberFailures)
{
$this->numberTokensSuccess = $numberFailures;
}
/**
* set number of failures.
*
* @param $numberFailures
* @return MockGroupResponse
*/
public function setNumberFailure($numberFailures)
{
$this->numberTokensSuccess = $numberFailures;
return $this;
}
/**
* Get the number of device which thrown an error
*
* @return int
*/
public function numberFailure()
{
return $this->numberTokensFailure;
}
/**
* Get the number of device which thrown an error.
*
* @return int
*/
public function numberFailure()
{
return $this->numberTokensFailure;
}
/**
* add a token to the failed list
*
* @param $tokenFailed
*/
public function addTokenFailed($tokenFailed)
{
$this->tokensFailed[] = $tokenFailed;
}
/**
* add a token to the failed list.
*
* @param $tokenFailed
* @return MockGroupResponse
*/
public function addTokenFailed($tokenFailed)
{
$this->tokensFailed[] = $tokenFailed;
return $this;
}
/**
* Get all token in group that fcm cannot reach
*
* @return array
*/
public function tokensFailed()
{
return $this->tokensFailed;
}
}
/**
* Get all token in group that fcm cannot reach.
*
* @return array
*/
public function tokensFailed()
{
return $this->tokensFailed;
}
/**
* @return string
*/
public function getTo()
{
return $this->to;
}
/**
* @param string $to
* @return MockGroupResponse
*/
public function setTo($to)
{
$this->to = $to;
return $this;
}
}

View File

@@ -1,86 +1,94 @@
<?php namespace LaravelFCM\Mocks;
<?php
namespace LaravelFCM\Mocks;
use LaravelFCM\Response\TopicResponseContract;
/**
* Class MockTopicResponse **Only use it for testing**
*
* @package LaravelFCM\Response
* Class MockTopicResponse **Only use it for testing**.
*/
class MockTopicResponse implements TopicResponseContract {
class MockTopicResponse implements TopicResponseContract
{
/**
* @internal
*
* @var string
*/
protected $topic;
/**
* @internal
*
* @var string
*/
protected $messageId;
/**
* @internal
* @var string
*/
protected $topic;
/**
* @internal
*
* @var string
*/
protected $error;
/**
* @internal
* @var string
*/
protected $messageId;
/**
* @internal
*
* @var bool
*/
protected $needRetry = false;
/**
* @internal
* @var string
*/
protected $error;
/**
* if success set a message id.
*
* @param $messageId
* @return MockTopicResponse
*/
public function setSuccess($messageId)
{
$this->messageId = $messageId;
return $this;
}
/**
* @internal
* @var bool
*/
protected $needRetry = false;
/**
* true if topic sent with success.
*
* @return bool
*/
public function isSuccess()
{
return (bool) $this->messageId;
}
/**
* if success set a message id
*
* @param $messageId
*/
public function setSuccess($messageId)
{
$this->messageId = $messageId;
}
/**
* set error.
*
* @param $error
* @return MockTopicResponse
*/
public function setError($error)
{
$this->error = $error;
return $this;
}
/**
* true if topic sent with success
*
* @return bool
*/
public function isSuccess()
{
return (bool) $this->messageId;
}
/**
* return error message
* you should test if it's necessary to resent it.
*
* @return string error
*/
public function error()
{
$this->error;
}
/**
* set error
* @param $error
*/
public function setError($error)
{
$this->error = $error;
}
/**
* return error message
* you should test if it's necessary to resent it
*
* @return string error
*/
public function error()
{
$this->error;
}
/**
* return true if it's necessary resent it using exponential backoff
*
* @return bool
*/
public function shouldRetry()
{
$this->error;
}
}
/**
* return true if it's necessary resent it using exponential backoff.
*
* @return bool
*/
public function shouldRetry()
{
$this->error;
}
}