update v1.0.7.9 R.C.

This is a Release Candidate. We are still testing.
This commit is contained in:
Sujit Prasad
2016-08-03 20:04:36 +05:30
parent 8b6b924d09
commit ffa56a43cb
3830 changed files with 181529 additions and 495353 deletions

View File

@@ -0,0 +1,3 @@
<?php
require_once __DIR__.'/vendor/autoload.php';

View File

@@ -0,0 +1,6 @@
<?php
$runner->addTestsFromDirectory(__DIR__.'/tests/units');
$script->noCodeCoverageForNamespaces('mageekguy', 'Symfony');
$script->bootstrapFile(__DIR__.DIRECTORY_SEPARATOR.'.atoum.bootstrap.php');

View File

@@ -0,0 +1,4 @@
bin
composer.lock
vendor/
web/

View File

@@ -0,0 +1,22 @@
language: php
php:
- 5.3
- 5.4
- 5.5
before_script:
- wget http://getcomposer.org/composer.phar
- php composer.phar install --dev --prefer-source
script:
- bin/atoum
notifications:
email:
recipients:
- cedric@dugat.me
on_success: change
on_failure: change
irc:
- "irc.freenode.org#slynett"

21
vendor/sly/notification-pusher/LICENSE vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2013 Cédric Dugat (cedric@dugat.me)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,44 @@
# NotificationPusher
Standalone PHP library for easy devices message notifications push.
[![Latest Stable Version](https://poser.pugx.org/sly/notification-pusher/v/stable.png)](https://packagist.org/packages/sly/notification-pusher)
[![Total Downloads](https://poser.pugx.org/sly/notification-pusher/downloads.png)](https://packagist.org/packages/sly/notification-pusher)
[![Build Status](https://secure.travis-ci.org/Ph3nol/NotificationPusher.png)](http://travis-ci.org/Ph3nol/NotificationPusher)
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/4f6f80c4-281a-4903-bf4c-1eb264995dbd/big.png)](https://insight.sensiolabs.com/projects/4f6f80c4-281a-4903-bf4c-1eb264995dbd)
**Feel free to contribute! Thanks.**
## Requirements
* PHP 5.3+
* PHP Curl and OpenSSL modules
* Specific adapters requirements (like APNS certificate, GCM API key, etc.)
## Today available adapters
* APNS (Apple)
* GCM (Android)
## Documentation and examples
* [Installation](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/installation.md)
* [Getting started](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/getting-started.md)
* [APNS adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/apns-adapter.md)
* [GCM adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/gcm-adapter.md)
* [Create an adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/create-an-adapter.md)
* [Push from CLI](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/push-from-cli.md)
## Todo
* Add new features (custom APNS payloads, GCM custom options, etc.)
* Add new adapters (like Blackberry and Windows phones)
* Write more documentation and examples
## 1.x users
Old version is still available from [1.x branch](https://github.com/Ph3nol/NotificationPusher/tree/1.x), with dedicated declared tag.
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/Ph3nol/notificationpusher/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

View File

@@ -0,0 +1,38 @@
{
"name": "sly/notification-pusher",
"description": "Standalone PHP library for easy devices notifications push.",
"keywords": ["apple", "iphone", "apns", "android", "gcm", "notification", "message", "push", "pusher"],
"homepage": "https://github.com/Ph3nol/NotificationPusher",
"type": "standalone",
"license": "MIT",
"authors": [
{
"name": "Cédric Dugat",
"email": "cedric@dugat.me"
},
{
"name": "Contributors",
"homepage": "https://github.com/Ph3nol/NotificationPusher/contributors"
}
],
"require": {
"php": ">=5.3.2",
"symfony/options-resolver": ">=2.3",
"symfony/console": ">=2.3",
"symfony/process": ">=2.3",
"zendframework/zendservice-apple-apns": "1.*",
"zendframework/zendservice-google-gcm": "1.*"
},
"require-dev": {
"atoum/atoum": "dev-master"
},
"config": {
"bin-dir": "bin"
},
"autoload": {
"psr-0": {
"Sly": ["src/"]
}
}
}

View File

@@ -0,0 +1,147 @@
# NotificationPusher - Documentation
## APNS adapter
[APNS](http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Introduction.html) adapter is used to push notification to Apple devices.
### Basic notification push example
``` php
<?php
require_once '/path/to/vendor/autoload.php';
use Sly\NotificationPusher\PushManager,
Sly\NotificationPusher\Adapter\Apns as ApnsAdapter,
Sly\NotificationPusher\Collection\DeviceCollection,
Sly\NotificationPusher\Model\Device,
Sly\NotificationPusher\Model\Message,
Sly\NotificationPusher\Model\Push
;
// First, instantiate the manager.
//
// Example for production environment:
// $pushManager = new PushManager(PushManager::ENVIRONMENT_PRODUCTION);
//
// Development one by default (without argument).
$pushManager = new PushManager(PushManager::ENVIRONMENT_DEV);
// Then declare an adapter.
$apnsAdapter = new ApnsAdapter(array(
'certificate' => '/path/to/your/apns-certificate.pem',
));
// Set the device(s) to push the notification to.
$devices = new DeviceCollection(array(
new Device('Token1'),
// ...
));
// Then, create the push skel.
$message = new Message('This is a basic example of push.');
// Finally, create and add the push to the manager, and push it!
$push = new Push($apnsAdapter, $devices, $message);
$pushManager->add($push);
$pushManager->push();
```
### Custom notification push example
``` php
<?php
require_once '/path/to/vendor/autoload.php';
use Sly\NotificationPusher\PushManager,
Sly\NotificationPusher\Adapter\Apns as ApnsAdapter,
Sly\NotificationPusher\Collection\DeviceCollection,
Sly\NotificationPusher\Model\Device,
Sly\NotificationPusher\Model\Message,
Sly\NotificationPusher\Model\Push
;
// First, instantiate the manager.
//
// Example for production environment:
// $pushManager = new PushManager(PushManager::ENVIRONMENT_PRODUCTION);
//
// Development one by default (without argument).
$pushManager = new PushManager(PushManager::ENVIRONMENT_DEV);
// Then declare an adapter.
$apnsAdapter = new ApnsAdapter(array(
'certificate' => '/path/to/your/apns-certificate.pem',
'passPhrase' => 'example',
));
// Set the device(s) to push the notification to.
$devices = new DeviceCollection(array(
new Device('Token1', array('badge' => 5)),
new Device('Token2', array('badge' => 1)),
new Device('Token3'),
));
// Then, create the push skel.
$message = new Message('This is an example.', array(
'badge' => 1,
'sound' => 'example.aiff',
'actionLocKey' => 'Action button title!',
'locKey' => 'localized key',
'locArgs' => array(
'localized args',
'localized args',
'localized args'
),
'launchImage' => 'image.jpg',
'custom' => array('custom data' => array(
'we' => 'want', 'send to app'
))
));
// Finally, create and add the push to the manager, and push it!
$push = new Push($apnsAdapter, $devices, $message);
$pushManager->add($push);
$pushManager->push(); // Returns a collection of notified devices
```
### Feedback example
The feedback service is used to list tokens of devices which not have your application anymore.
``` php
<?php
require_once '/path/to/vendor/autoload.php';
use Sly\NotificationPusher\PushManager,
Sly\NotificationPusher\Adapter\Apns as ApnsAdapter
;
// First, instantiate the manager.
//
// Example for production environment:
// $pushManager = new PushManager(PushManager::ENVIRONMENT_PRODUCTION);
//
// Development one by default (without argument).
$pushManager = new PushManager(PushManager::ENVIRONMENT_DEV);
// Then declare an adapter.
$apnsAdapter = new ApnsAdapter(array(
'certificate' => '/path/to/your/apns-certificate.pem',
));
$feedback = $pushManager->getFeedback($apnsAdapter); // Returns an array of Token + DateTime couples
```
## Documentation index
* [Installation](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/installation.md)
* [Getting started](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/getting-started.md)
* APNS adapter
* [GCM adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/gcm-adapter.md)
* [Create an adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/create-an-adapter.md)
* [Push from CLI](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/push-from-cli.md)

View File

@@ -0,0 +1,22 @@
# NotificationPusher - Documentation
## Create an adapter
To create your own adapter, just create a class with taking care to extends `\Sly\NotificationPusher\Adapter\BaseAdapter`
and implements `\Sly\NotificationPusher\Adapter\AdapterInterface` which contains some required methods:
* `push`: contains the adapter logic to push notifications
* `supports`: return the token condition for using the adapter
* `getDefaultParameters`: returns default parameters used by the adapter
* `getRequiredParameters`: returns required parameters used by the adapter
Feel free to observe [existent adapters](https://github.com/Ph3nol/NotificationPusher/tree/master/src/Sly/NotificationPusher/Adapter) for concrete example.
## Documentation index
* [Installation](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/installation.md)
* [Getting started](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/getting-started.md)
* [APNS adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/apns-adapter.md)
* [GCM adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/gcm-adapter.md)
* Create an adapter
* [Push from CLI](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/push-from-cli.md)

View File

@@ -0,0 +1,58 @@
# NotificationPusher - Documentation
## GCM adapter
[GCM](http://developer.android.com/google/gcm/gs.html) adapter is used to push notification to Google/Android devices.
### Custom notification push example
``` php
<?php
require_once '/path/to/vendor/autoload.php';
use Sly\NotificationPusher\PushManager,
Sly\NotificationPusher\Adapter\Gcm as GcmAdapter,
Sly\NotificationPusher\Collection\DeviceCollection,
Sly\NotificationPusher\Model\Device,
Sly\NotificationPusher\Model\Message,
Sly\NotificationPusher\Model\Push
;
// First, instantiate the manager.
//
// Example for production environment:
// $pushManager = new PushManager(PushManager::ENVIRONMENT_PRODUCTION);
//
// Development one by default (without argument).
$pushManager = new PushManager(PushManager::ENVIRONMENT_DEV);
// Then declare an adapter.
$gcmAdapter = new GcmAdapter(array(
'apiKey' => 'YourApiKey',
));
// Set the device(s) to push the notification to.
$devices = new DeviceCollection(array(
new Device('Token1'),
new Device('Token2'),
new Device('Token3'),
));
// Then, create the push skel.
$message = new Message('This is an example.');
// Finally, create and add the push to the manager, and push it!
$push = new Push($gcmAdapter, $devices, $message);
$pushManager->add($push);
$pushManager->push(); // Returns a collection of notified devices
```
## Documentation index
* [Installation](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/installation.md)
* [Getting started](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/getting-started.md)
* [APNS adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/apns-adapter.md)
* GCM adapter
* [Create an adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/create-an-adapter.md)
* [Push from CLI](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/push-from-cli.md)

View File

@@ -0,0 +1,87 @@
# NotificationPusher - Documentation
## Getting started
First, we are going to discover this library entities:
* Models (messages, pushes, devices)
* Adapters (APNS, GCM etc.)
* The Manager
Here is the basic principle of a notification push:
A **push** has 3 main elements: a composed **message**, some defined **devices** to notify
and an **adapter** matching with these devices.
The **manager** has to collect all push notifications and send them.
Here is how to translate this with code (just a little not-working example):
``` php
<?php
// First, instantiate the manager and declare an adapter.
$pushManager = new PushManager();
$exampleAdapter = new ApnsAdapter();
// Set the device(s) to push the notification to.
$devices = new DeviceCollection(array(
new Device('Token1'),
new Device('Token2'),
new Device('Token3'),
// ...
));
// Then, create the push skel.
$message = new Message('This is an example.');
// Finally, create and add the push to the manager, and push it!
$push = new Push($exampleAdapter, $devices, $message);
$pushManager->add($push);
$pushManager->push();
```
## More about the Message entity
Some general options can be passed to the message entity and be used by adapters.
A message pushed from APNS adapter can comport a "badge" or "sound" information which will be set with
instance constructor second argument:
``` php
<?php
$message = new Message('This is an example.', array(
'badge' => 1,
'sound' => 'example.aiff',
// ...
));
```
## More about the Device entity
The device can comport some dedicated informations that could be used by adapters.
For example, APNS adapter could want to know a device badge status for incrementing it with message's one.
Here is an example of this:
``` php
<?php
$message = new Message('This is an example.', array(
'badge' => 1,
// ...
));
$devices = new DeviceCollection(array(
new Device('Token1', array('badge' => 5)),
// ...
));
```
## Documentation index
* [Installation](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/installation.md)
* Getting started
* [APNS adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/apns-adapter.md)
* [GCM adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/gcm-adapter.md)
* [Create an adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/create-an-adapter.md)
* [Push from CLI](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/push-from-cli.md)

View File

@@ -0,0 +1,23 @@
# NotificationPusher - Documentation
## Installation
Use [Composer](http://getcomposer.org) to install this library.
Into your `composer.json` file, just include this library with adding:
```
"sly/notification-pusher": "2.x"
```
Then, run `composer update sly/notification-pusher` and enjoy.
## Documentation index
* Installation
* [Getting started](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/getting-started.md)
* [APNS adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/apns-adapter.md)
* [GCM adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/gcm-adapter.md)
* [Create an adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/create-an-adapter.md)
* [Push from CLI](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/push-from-cli.md)
* [Push from CLI](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/push-from-cli.md)

View File

@@ -0,0 +1,34 @@
# NotificationPusher - Documentation
## Push from CLI
For some reasons (tests or others), you could be happened to use pushing from CLI.
To do this, use `np` script (available at root directory) this way:
```
./np push <adapter> <token-or-registration-id> "Your message" --option1=value1 --option2=value2 ...
```
Each options matches with adapters required and optional ones.
Here is a concrete APNS adapter example:
```
./np push apns <token> "It's an example!" --certificate=/path/to/the/certificate.pem
```
Here is a concrete GCM adapter example:
```
./np push gcm <token> "It's an example!" --api-key=XXXXXXXXXX
```
## Documentation index
* [Installation](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/installation.md)
* [Getting started](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/getting-started.md)
* [APNS adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/apns-adapter.md)
* [GCM adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/gcm-adapter.md)
* [Create an adapter](https://github.com/Ph3nol/NotificationPusher/blob/master/doc/create-an-adapter.md)
* Push from CLI

13
vendor/sly/notification-pusher/np vendored Normal file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/env php
<?php
if (file_exists($a = __DIR__.'/../../autoload.php')) {
require_once $a;
} else {
require_once __DIR__.'/vendor/autoload.php';
}
use Sly\NotificationPusher\Console\Application;
$application = new Application();
$application->run();

View File

@@ -0,0 +1,54 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Adapter;
use Sly\NotificationPusher\Model\PushInterface;
/**
* AdapterInterface.
*
* @author Cédric Dugat <cedric@dugat.me>
*/
interface AdapterInterface
{
/**
* Push.
*
* @param \Sly\NotificationPusher\Model\PushInterface $push Push
*
* @return \Sly\NotificationPusher\Collection\DeviceCollection
*/
public function push(PushInterface $push);
/**
* Supports.
*
* @param string $token Token
*
* @return boolean
*/
public function supports($token);
/**
* Get default parameters.
*
* @return array
*/
public function getDefaultParameters();
/**
* Get required parameters.
*
* @return array
*/
public function getRequiredParameters();
}

View File

@@ -0,0 +1,196 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Adapter;
use Sly\NotificationPusher\Model\PushInterface;
use Sly\NotificationPusher\Model\MessageInterface;
use Sly\NotificationPusher\Model\DeviceInterface;
use Sly\NotificationPusher\Exception\AdapterException;
use Sly\NotificationPusher\Exception\PushException;
use Sly\NotificationPusher\Collection\DeviceCollection;
use ZendService\Apple\Apns\Client\AbstractClient as ServiceAbstractClient;
use ZendService\Apple\Apns\Client\Message as ServiceClient;
use ZendService\Apple\Apns\Message as ServiceMessage;
use ZendService\Apple\Apns\Message\Alert as ServiceAlert;
use ZendService\Apple\Apns\Response\Message as ServiceResponse;
use ZendService\Apple\Apns\Exception\RuntimeException as ServiceRuntimeException;
use ZendService\Apple\Apns\Client\Feedback as ServiceFeedbackClient;
/**
* APNS adapter.
*
* @uses \Sly\NotificationPusher\Adapter\BaseAdapter
* @uses \Sly\NotificationPusher\Adapter\AdapterInterface
*
* @author Cédric Dugat <cedric@dugat.me>
*/
class Apns extends BaseAdapter implements AdapterInterface
{
/**
* {@inheritdoc}
*
* @throws \Sly\NotificationPusher\Exception\AdapterException
*/
public function __construct(array $parameters = array())
{
parent::__construct($parameters);
$cert = $this->getParameter('certificate');
if (false === file_exists($cert)) {
throw new AdapterException(sprintf('Certificate %s does not exist', $cert));
}
}
/**
* {@inheritdoc}
*
* @throws \Sly\NotificationPusher\Exception\PushException
*/
public function push(PushInterface $push)
{
$client = $this->getOpenedClient(new ServiceClient());
$pushedDevices = new DeviceCollection();
foreach ($push->getDevices() as $device) {
$message = $this->getServiceMessageFromOrigin($device, $push->getMessage());
try {
$this->response = $client->send($message);
} catch (ServiceRuntimeException $e) {
throw new PushException($e->getMessage());
}
if (ServiceResponse::RESULT_OK === $this->response->getCode()) {
$pushedDevices->add($device);
}
}
$client->close();
return $pushedDevices;
}
/**
* Feedback.
*
* @return array
*/
public function getFeedback()
{
$client = $this->getOpenedClient(new ServiceFeedbackClient());
$responses = array();
$serviceResponses = $client->feedback();
$client->close();
foreach ($serviceResponses as $response) {
$responses[$response->getToken()] = new \DateTime(date("c", $response->getTime()));
}
return $responses;
}
/**
* Get opened client.
*
* @param \ZendService\Apple\Apns\Client\AbstractClient $client Client
*
* @return \ZendService\Apple\Apns\Client\AbstractClient
*/
public function getOpenedClient(ServiceAbstractClient $client)
{
$client->open(
$this->isProductionEnvironment() ? ServiceClient::PRODUCTION_URI : ServiceClient::SANDBOX_URI,
$this->getParameter('certificate'),
$this->getParameter('passPhrase')
);
return $client;
}
/**
* Get service message from origin.
*
* @param \Sly\NotificationPusher\Model\DeviceInterface $device Device
* @param \Sly\NotificationPusher\Model\MessageInterface $message Message
*
* @return \ZendService\Apple\Apns\Message
*/
public function getServiceMessageFromOrigin(DeviceInterface $device, MessageInterface $message)
{
$badge = ($message->hasOption('badge'))
? (int) ($message->getOption('badge') + $device->getParameter('badge', 0))
: 0
;
$sound = $message->getOption('sound', 'bingbong.aiff');
$alert = new ServiceAlert(
$message->getText(),
$message->getOption('actionLocKey'),
$message->getOption('locKey'),
$message->getOption('locArgs'),
$message->getOption('launchImage')
);
if ($actionLocKey = $message->getOption('actionLocKey')) {
$alert->setActionLocKey($actionLocKey);
}
if ($locKey = $message->getOption('locKey')) {
$alert->setLocKey($locKey);
}
if ($locArgs = $message->getOption('locArgs')) {
$alert->setLocArgs($locArgs);
}
if ($launchImage = $message->getOption('launchImage')) {
$alert->setLaunchImage($launchImage);
}
$serviceMessage = new ServiceMessage();
$serviceMessage->setId(sha1($device->getToken().$message->getText()));
$serviceMessage->setAlert($alert);
$serviceMessage->setToken($device->getToken());
$serviceMessage->setBadge($badge);
$serviceMessage->setCustom($message->getOption('custom', array()));
if (null !== $sound) {
$serviceMessage->setSound($sound);
}
return $serviceMessage;
}
/**
* {@inheritdoc}
*/
public function supports($token)
{
return (ctype_xdigit($token) && 64 == strlen($token));
}
/**
* {@inheritdoc}
*/
public function getDefaultParameters()
{
return array('passPhrase' => null);
}
/**
* {@inheritdoc}
*/
public function getRequiredParameters()
{
return array('certificate');
}
}

View File

@@ -0,0 +1,130 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Adapter;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Sly\NotificationPusher\Model\BaseParameteredModel;
use Sly\NotificationPusher\PushManager;
/**
* BaseAdapter.
*
* @author Cédric Dugat <cedric@dugat.me>
*/
abstract class BaseAdapter extends BaseParameteredModel
{
/**
* @var string
*/
protected $adapterKey;
/**
* @var string
*/
protected $environment;
/**
* @var mixed
*/
protected $response;
/**
* Constructor.
*
* @param array $parameters Adapter specific parameters
*/
public function __construct(array $parameters = array())
{
$resolver = new OptionsResolver();
$resolver->setDefaults($this->getDefaultParameters());
$resolver->setRequired($this->getRequiredParameters());
$reflectedClass = new \ReflectionClass($this);
$this->adapterKey = lcfirst($reflectedClass->getShortName());
$this->parameters = $resolver->resolve($parameters);
}
/**
* __toString.
*
* @return string
*/
public function __toString()
{
return ucfirst($this->getAdapterKey());
}
/**
* Return the original response.
*
* @return mixed
*/
public function getResponse()
{
return $this->response;
}
/**
* Get AdapterKey.
*
* @return string
*/
public function getAdapterKey()
{
return $this->adapterKey;
}
/**
* Get Environment.
*
* @return string
*/
public function getEnvironment()
{
return $this->environment;
}
/**
* Set Environment.
*
* @param string $environment Environment value to set
*
* @return \Sly\NotificationPusher\Adapter\AdapterInterface
*/
public function setEnvironment($environment)
{
$this->environment = $environment;
return $this;
}
/**
* isDevelopmentEnvironment.
*
* @return boolean
*/
public function isDevelopmentEnvironment()
{
return (PushManager::ENVIRONMENT_DEV === $this->getEnvironment());
}
/**
* isProductionEnvironment.
*
* @return boolean
*/
public function isProductionEnvironment()
{
return (PushManager::ENVIRONMENT_PROD === $this->getEnvironment());
}
}

View File

@@ -0,0 +1,181 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Adapter;
use Sly\NotificationPusher\Model\PushInterface;
use Sly\NotificationPusher\Model\MessageInterface;
use Sly\NotificationPusher\Collection\DeviceCollection;
use Sly\NotificationPusher\Exception\PushException;
use Zend\Http\Client as HttpClient;
use Zend\Http\Client\Adapter\Socket as HttpSocketAdapter;
use ZendService\Google\Gcm\Client as ServiceClient;
use ZendService\Google\Gcm\Message as ServiceMessage;
use ZendService\Google\Exception\RuntimeException as ServiceRuntimeException;
use InvalidArgumentException;
/**
* GCM adapter.
*
* @uses \Sly\NotificationPusher\Adapter\BaseAdapter
* @uses \Sly\NotificationPusher\Adapter\AdapterInterface
*
* @author Cédric Dugat <cedric@dugat.me>
*/
class Gcm extends BaseAdapter implements AdapterInterface
{
/**
* @var \Zend\Http\Client
*/
private $httpClient;
/**
* {@inheritdoc}
*/
public function supports($token)
{
return (bool) preg_match('/[0-9a-zA-Z\-\_]/i', $token);
}
/**
* {@inheritdoc}
*
* @throws \Sly\NotificationPusher\Exception\PushException
*/
public function push(PushInterface $push)
{
$client = $this->getOpenedClient(new ServiceClient());
$pushedDevices = new DeviceCollection();
$tokens = array_chunk($push->getDevices()->getTokens(), 100);
foreach ($tokens as $tokensRange) {
$message = $this->getServiceMessageFromOrigin($tokensRange, $push->getMessage());
try {
$this->response = $client->send($message);
} catch (ServiceRuntimeException $e) {
throw new PushException($e->getMessage());
}
if ((bool) $this->response->getSuccessCount()) {
foreach ($tokensRange as $token) {
$pushedDevices->add($push->getDevices()->get($token));
}
}
}
return $pushedDevices;
}
/**
* Get opened client.
*
* @param \ZendService\Google\Gcm\Client $client Client
*
* @return \ZendService\Google\Gcm\Client
*/
public function getOpenedClient(ServiceClient $client)
{
$client->setApiKey($this->getParameter('apiKey'));
if ($this->httpClient !== null) {
$client->setHttpClient($this->httpClient);
}
return $client;
}
/**
* Get service message from origin.
*
* @param array $tokens Tokens
* @param \Sly\NotificationPusher\Model\MessageInterface $message Message
*
* @return \ZendService\Google\Gcm\Message
*/
public function getServiceMessageFromOrigin(array $tokens, MessageInterface $message)
{
$data = $message->getOptions();
$data['message'] = $message->getText();
$serviceMessage = new ServiceMessage();
$serviceMessage->setRegistrationIds($tokens);
$serviceMessage->setData($data);
$serviceMessage->setCollapseKey($this->getParameter('collapseKey'));
$serviceMessage->setRestrictedPackageName($this->getParameter('restrictedPackageName'));
$serviceMessage->setDelayWhileIdle($this->getParameter('delayWhileIdle', false));
$serviceMessage->setTimeToLive($this->getParameter('ttl', 600));
$serviceMessage->setDryRun($this->getParameter('dryRun', false));
return $serviceMessage;
}
/**
* {@inheritdoc}
*/
public function getDefaultParameters()
{
return array();
}
/**
* {@inheritdoc}
*/
public function getRequiredParameters()
{
return array('apiKey');
}
/**
* Get the current Zend Http Client instance.
*
* @return HttpClient
*/
public function getHttpClient()
{
return $this->httpClient;
}
/**
* Overrides the default Http Client.
*
* @param HttpClient $client
*/
public function setHttpClient(HttpClient $client)
{
$this->httpClient = $client;
}
/**
* Send custom parameters to the Http Adapter without overriding the Http Client.
*
* @param array $config
*
* @throws \InvalidArgumentException
*/
public function setAdapterParameters(array $config = array())
{
if (!is_array($config) || empty($config)) {
throw new InvalidArgumentException('$config must be an associative array with at least 1 item.');
}
if ($this->httpClient === null) {
$this->httpClient = new HttpClient();
$this->httpClient->setAdapter(new HttpSocketAdapter());
}
$this->httpClient->getAdapter()->setOptions($config);
}
}

View File

@@ -0,0 +1,66 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Collection;
/**
* AbstractCollection.
*
* @uses \IteratorAggregate
* @author Cédric Dugat <cedric@dugat.me>
*/
abstract class AbstractCollection
{
/**
* @var \ArrayIterator
*/
protected $coll;
/**
* Get.
*
* @param string $key Key
*
* @return \Sly\NotificationPusher\Model\MessageInterface|false
*/
public function get($key)
{
return isset($this->coll[$key]) ? $this->coll[$key] : false;
}
/**
* Count.
*
* @return integer
*/
public function count()
{
return count($this->getIterator());
}
/**
* isEmpty.
*
* @return boolean
*/
public function isEmpty()
{
return (bool) $this->count();
}
/**
* Clear categories.
*/
public function clear()
{
$this->coll = new \ArrayIterator();
}
}

View File

@@ -0,0 +1,70 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Collection;
use Sly\NotificationPusher\Model\DeviceInterface;
/**
* DeviceCollection.
*
* @uses \Sly\NotificationPusher\Collection\AbstractCollection
* @uses \IteratorAggregate
* @author Cédric Dugat <cedric@dugat.me>
*/
class DeviceCollection extends AbstractCollection implements \IteratorAggregate
{
/**
* Constructor.
*
* @param array $devices Devices
*/
public function __construct(array $devices = array())
{
$this->coll = new \ArrayIterator();
foreach ($devices as $device) {
$this->add($device);
}
}
/**
* @return \ArrayIterator
*/
public function getIterator()
{
return $this->coll;
}
/**
* @param \Sly\NotificationPusher\Model\DeviceInterface $device Device
*/
public function add(DeviceInterface $device)
{
$this->coll[$device->getToken()] = $device;
}
/**
* Get tokens.
*
* @return array
*/
public function getTokens()
{
$tokens = array();
foreach ($this as $token => $device) {
$tokens[] = $token;
}
return array_unique(array_filter($tokens));
}
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Collection;
use Sly\NotificationPusher\Model\MessageInterface;
/**
* MessageCollection.
*
* @uses \Sly\NotificationPusher\Collection\AbstractCollection
* @uses \IteratorAggregate
* @author Cédric Dugat <cedric@dugat.me>
*/
class MessageCollection extends AbstractCollection implements \IteratorAggregate
{
/**
* Constructor.
*/
public function __construct()
{
$this->coll = new \ArrayIterator();
}
/**
* @return \ArrayIterator
*/
public function getIterator()
{
return $this->coll;
}
/**
* @param \Sly\NotificationPusher\Model\MessageInterface $message Message
*/
public function add(MessageInterface $message)
{
$this->coll[] = $message;
}
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Collection;
use Sly\NotificationPusher\Model\PushInterface;
/**
* PushCollection.
*
* @uses \Sly\NotificationPusher\Collection\AbstractCollection
* @uses \IteratorAggregate
* @author Cédric Dugat <cedric@dugat.me>
*/
class PushCollection extends AbstractCollection implements \IteratorAggregate
{
/**
* Constructor.
*/
public function __construct()
{
$this->coll = new \ArrayIterator();
}
/**
* @return \ArrayIterator
*/
public function getIterator()
{
return $this->coll;
}
/**
* @param \Sly\NotificationPusher\Model\PushInterface $push Push
*/
public function add(PushInterface $push)
{
$this->coll[] = $push;
}
}

View File

@@ -0,0 +1,37 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Console;
use Symfony\Component\Console\Application as BaseApplication;
use Sly\NotificationPusher\NotificationPusher;
use Sly\NotificationPusher\Console\Command\PushCommand;
/**
* Application.
*
* @uses \Symfony\Component\Console\Application
* @author Cédric Dugat <cedric@dugat.me>
*/
class Application extends BaseApplication
{
/**
* Constructor.
*/
public function __construct()
{
error_reporting(-1);
parent::__construct('NotificationPusher version', NotificationPusher::VERSION);
$this->add(new PushCommand());
}
}

View File

@@ -0,0 +1,160 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Console\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Sly\NotificationPusher\PushManager;
use Sly\NotificationPusher\Model\Device;
use Sly\NotificationPusher\Model\Message;
use Sly\NotificationPusher\Model\Push;
use Sly\NotificationPusher\Exception\AdapterException;
use Doctrine\Common\Util\Inflector;
/**
* PushCommand.
*
* @uses \Symfony\Component\Console\Command\Command
* @author Cédric Dugat <cedric@dugat.me>
*/
class PushCommand extends Command
{
/**
* @see Command
*/
protected function configure()
{
parent::configure();
$this
->setName('push')
->setDescription('Manual notification push')
->addArgument(
'adapter',
InputArgument::REQUIRED,
'Adapter (apns, gcm, specific class name, ...)'
)
->addArgument(
'token',
InputArgument::REQUIRED,
'Device Token or Registration ID'
)
->addArgument(
'message',
InputArgument::REQUIRED,
'Message'
)
->addOption(
'certificate',
null,
InputOption::VALUE_OPTIONAL,
'Certificate path (for APNS adapter)'
)
->addOption(
'api-key',
null,
InputOption::VALUE_OPTIONAL,
'API key (for GCM adapter)'
)
->addOption(
'env',
PushManager::ENVIRONMENT_DEV,
InputOption::VALUE_OPTIONAL,
sprintf(
'Environment (%s, %s)',
PushManager::ENVIRONMENT_DEV,
PushManager::ENVIRONMENT_PROD
)
);
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$adapter = $this->getReadyAdapter($input, $output);
$pushManager = new PushManager($input->getOption('env'));
$message = new Message('This is an example.');
$push = new Push($adapter, new Device($input->getArgument('token')), $message);
$pushManager->add($push);
$pushManager->push();
}
/**
* Get adapter class from argument.
*
* @param string $argument Given argument
*
* @return string
*
* @throws AdapterException When given adapter class doesn't exist
*/
private function getAdapterClassFromArgument($argument)
{
if (!class_exists($adapterClass = $argument) &&
!class_exists($adapterClass = '\\Sly\\NotificationPusher\\Adapter\\'.ucfirst($argument))) {
throw new AdapterException(
sprintf(
'Adapter class %s does not exist',
$adapterClass
)
);
}
return $adapterClass;
}
/**
* {@inheritdoc}
*
* @return \Sly\NotificationPusher\Adapter\AdapterInterface
*/
private function getReadyAdapter(InputInterface $input, OutputInterface $output)
{
$adapterClass = $this->getAdapterClassFromArgument($input->getArgument('adapter'));
try {
$adapter = new $adapterClass();
} catch (\Exception $e) {
$adapterData = array();
preg_match_all('/"(.*)"/i', $e->getMessage(), $matches);
foreach ($matches[1] as $match) {
$optionKey = str_replace('_', '-', Inflector::tableize($match));
$option = $input->getOption($optionKey);
if (!$option) {
throw new AdapterException(
sprintf(
'The option "%s" is needed by %s adapter',
$optionKey,
$adapterClass
)
);
}
$adapterData[$match] = $option;
}
$adapter = new $adapterClass($adapterData);
}
return $adapter;
}
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Exception;
use Sly\NotificationPusher\Exception\ExceptionInterface;
/**
* AdapterException.
*
* @uses \RuntimeException
* @uses \Sly\NotificationPusher\Exception\ExceptionInterface
*
* @author Cédric Dugat <cedric@dugat.me>
*/
class AdapterException extends \RuntimeException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Exception;
/**
* ExceptionInterface.
*
* @author Cédric Dugat <cedric@dugat.me>
*/
interface ExceptionInterface
{
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Exception;
use Sly\NotificationPusher\Exception\ExceptionInterface;
/**
* InvalidException.
*
* @uses \RuntimeException
* @uses \Sly\NotificationPusher\Exception\ExceptionInterface
*
* @author Cédric Dugat <cedric@dugat.me>
*/
class InvalidException extends \RuntimeException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Exception;
use Sly\NotificationPusher\Exception\ExceptionInterface;
/**
* PushException.
*
* @uses \RuntimeException
* @uses \Sly\NotificationPusher\Exception\ExceptionInterface
*
* @author Cédric Dugat <cedric@dugat.me>
*/
class PushException extends \RuntimeException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Exception;
use Sly\NotificationPusher\Exception\ExceptionInterface;
/**
* RuntimeException.
*
* @uses \RuntimeException
* @uses \Sly\NotificationPusher\Exception\ExceptionInterface
*
* @author Cédric Dugat <cedric@dugat.me>
*/
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,89 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Model;
/**
* BaseOptionedModel.
*
* @author Cédric Dugat <cedric@dugat.me>
*/
abstract class BaseOptionedModel
{
/**
* @var array
*/
protected $options = array();
/**
* Get options.
*
* @return array
*/
public function getOptions()
{
return $this->options;
}
/**
* Has option.
*
* @param string $key Key
*
* @return boolean
*/
public function hasOption($key)
{
return array_key_exists($key, $this->options);
}
/**
* Get option.
*
* @param string $key Key
* @param mixed $default Default
*
* @return mixed
*/
public function getOption($key, $default = null)
{
return $this->hasOption($key) ? $this->options[$key] : $default;
}
/**
* Set options.
*
* @param array $options Options
*
* @return \Sly\NotificationPusher\Model\BaseOptionedModel
*/
public function setOptions($options)
{
$this->options = $options;
return $this;
}
/**
* Set option.
*
* @param string $key Key
* @param mixed $value Value
*
* @return mixed
*/
public function setOption($key, $value)
{
$this->options[$key] = $value;
return $value;
}
}

View File

@@ -0,0 +1,89 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Model;
/**
* BaseParameteredModel.
*
* @author Cédric Dugat <cedric@dugat.me>
*/
abstract class BaseParameteredModel
{
/**
* @var array
*/
protected $parameters = array();
/**
* Get parameters.
*
* @return array
*/
public function getParameters()
{
return $this->parameters;
}
/**
* Has parameter.
*
* @param string $key Key
*
* @return boolean
*/
public function hasParameter($key)
{
return array_key_exists($key, $this->parameters);
}
/**
* Get parameter.
*
* @param string $key Key
* @param mixed $default Default
*
* @return mixed
*/
public function getParameter($key, $default = null)
{
return $this->hasParameter($key) ? $this->parameters[$key] : $default;
}
/**
* Set parameters.
*
* @param array $parameters Parameters
*
* @return \Sly\NotificationPusher\Model\BaseParameteredModel
*/
public function setParameters($parameters)
{
$this->parameters = $parameters;
return $this;
}
/**
* Set parameter.
*
* @param string $key Key
* @param mixed $value Value
*
* @return mixed
*/
public function setParameter($key, $value)
{
$this->parameters[$key] = $value;
return $value;
}
}

View File

@@ -0,0 +1,61 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Model;
/**
* Device.
*
* @author Cédric Dugat <cedric@dugat.me>
*/
class Device extends BaseParameteredModel implements DeviceInterface
{
/**
* @var string
*/
private $token;
/**
* Constructor.
*
* @param string $token Token
* @param array $parameters Parameters
*/
public function __construct($token, array $parameters = array())
{
$this->token = $token;
$this->parameters = $parameters;
}
/**
* Get token.
*
* @return string
*/
public function getToken()
{
return $this->token;
}
/**
* Set token.
*
* @param string $token Token
*
* @return \Sly\NotificationPusher\Model\DeviceInterface
*/
public function setToken($token)
{
$this->token = $token;
return $this;
}
}

View File

@@ -0,0 +1,36 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Model;
/**
* DeviceInterface
*
* @author Cédric Dugat <cedric@dugat.me>
*/
interface DeviceInterface
{
/**
* Get token.
*
* @return string
*/
public function getToken();
/**
* Set token.
*
* @param string $token Token
*
* @return \Sly\NotificationPusher\Model\DeviceInterface
*/
public function setToken($token);
}

View File

@@ -0,0 +1,61 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Model;
/**
* Message.
*
* @author Cédric Dugat <cedric@dugat.me>
*/
class Message extends BaseOptionedModel implements MessageInterface
{
/**
* @var string
*/
private $text;
/**
* Constructor.
*
* @param string $text Text
* @param array $options Options
*/
public function __construct($text, array $options = array())
{
$this->text = $text;
$this->options = $options;
}
/**
* Get Text.
*
* @return string
*/
public function getText()
{
return $this->text;
}
/**
* Set Text.
*
* @param string $text Text
*
* @return \Sly\NotificationPusher\Model\MessageInterface
*/
public function setText($text)
{
$this->text = $text;
return $this;
}
}

View File

@@ -0,0 +1,36 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Model;
/**
* MessageInterface
*
* @author Cédric Dugat <cedric@dugat.me>
*/
interface MessageInterface
{
/**
* Get Text.
*
* @return string
*/
public function getText();
/**
* Set Text.
*
* @param string $text Text
*
* @return \Sly\NotificationPusher\Model\MessageInterface
*/
public function setText($text);
}

View File

@@ -0,0 +1,246 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Model;
use Sly\NotificationPusher\Collection\DeviceCollection;
use Sly\NotificationPusher\Adapter\AdapterInterface;
use Sly\NotificationPusher\Model\DeviceInterface;
use Sly\NotificationPusher\Model\MessageInterface;
use Sly\NotificationPusher\Exception\AdapterException;
/**
* Push.
*
* @author Cédric Dugat <cedric@dugat.me>
*/
class Push extends BaseOptionedModel implements PushInterface
{
/**
* @var string
*/
private $status;
/**
* @var \Sly\NotificationPusher\Adapter\AdapterInterface
*/
private $adapter;
/**
* @var \Sly\NotificationPusher\Model\MessageInterface
*/
private $message;
/**
* @var \Sly\NotificationPusher\Collection\DeviceCollection
*/
private $devices;
/**
* @var \DateTime
*/
private $pushedAt;
/**
* Constructor.
*
* @param \Sly\NotificationPusher\Adapter\AdapterInterface $adapter Adapter
* @param DeviceInterface|DeviceCollection $devices Device(s)
* @param \Sly\NotificationPusher\Model\MessageInterface $message Message
* @param array $options Options
*
* Options are adapters specific ones, like Apns "badge" or "sound" option for example.
* Of course, they can be more general.
*
* @throws \Sly\NotificationPusher\Exception\AdapterException
*/
public function __construct(AdapterInterface $adapter, $devices, MessageInterface $message, array $options = array())
{
if ($devices instanceof DeviceInterface) {
$devices = new DeviceCollection(array($devices));
}
$this->adapter = $adapter;
$this->devices = $devices;
$this->message = $message;
$this->options = $options;
$this->status = self::STATUS_PENDING;
$this->checkDevicesTokens();
}
/**
* Check devices tokens.
*/
private function checkDevicesTokens()
{
$devices = $this->getDevices();
$adapter = $this->getAdapter();
foreach ($devices as $device) {
if (false === $adapter->supports($device->getToken())) {
throw new AdapterException(
sprintf(
'Adapter %s does not supports %s token\'s device',
(string) $adapter,
$device->getToken()
)
);
}
}
}
/**
* Get Status.
*
* @return string
*/
public function getStatus()
{
return $this->status;
}
/**
* Set Status.
*
* @param string $status Status
*
* @return \Sly\NotificationPusher\Model\PushInterface
*/
public function setStatus($status)
{
$this->status = $status;
return $this;
}
/**
* isPushed.
*
* @return boolean
*/
public function isPushed()
{
return (bool) (self::STATUS_PUSHED === $this->status);
}
/**
* Declare as pushed.
*
* @return \Sly\NotificationPusher\Model\PushInterface
*/
public function pushed()
{
$this->status = self::STATUS_PUSHED;
$this->pushedAt = new \DateTime();
return $this;
}
/**
* Get Adapter.
*
* @return \Sly\NotificationPusher\Adapter\AdapterInterface
*/
public function getAdapter()
{
return $this->adapter;
}
/**
* Set Adapter.
*
* @param \Sly\NotificationPusher\Adapter\AdapterInterface $adapter Adapter
*
* @return \Sly\NotificationPusher\Model\PushInterface
*/
public function setAdapter(AdapterInterface $adapter)
{
$this->adapter = $adapter;
return $this;
}
/**
* Get Message.
*
* @return \Sly\NotificationPusher\Model\MessageInterface
*/
public function getMessage()
{
return $this->message;
}
/**
* Set Message.
*
* @param \Sly\NotificationPusher\Model\MessageInterface $message Message
*
* @return \Sly\NotificationPusher\Model\PushInterface
*/
public function setMessage(MessageInterface $message)
{
$this->message = $message;
return $this;
}
/**
* Get Devices.
*
* @return \Sly\NotificationPusher\Collection\DeviceCollection
*/
public function getDevices()
{
return $this->devices;
}
/**
* Set Devices.
*
* @param \Sly\NotificationPusher\Collection\DeviceCollection $devices Devices
*
* @return \Sly\NotificationPusher\Model\PushInterface
*/
public function setDevices(DeviceCollection $devices)
{
$this->devices = $devices;
$this->checkDevicesTokens();
return $this;
}
/**
* Get PushedAt.
*
* @return \DateTime
*/
public function getPushedAt()
{
return $this->pushedAt;
}
/**
* Set PushedAt.
*
* @param \DateTime $pushedAt PushedAt
*
* @return \Sly\NotificationPusher\Model\PushInterface
*/
public function setPushedAt(\DateTime $pushedAt)
{
$this->pushedAt = $pushedAt;
return $this;
}
}

View File

@@ -0,0 +1,122 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher\Model;
use DateTime;
use Sly\NotificationPusher\Adapter\AdapterInterface;
use Sly\NotificationPusher\Collection\DeviceCollection;
/**
* PushInterface
*/
interface PushInterface
{
/**
* Constants define available statuses
*/
const STATUS_PENDING = 'pending';
const STATUS_PUSHED = 'sent';
/**
* Get Status.
*
* @return string
*/
public function getStatus();
/**
* Set Status.
*
* @param string $status Status
*
* @return PushInterface
*/
public function setStatus($status);
/**
* isPushed.
*
* @return boolean
*/
public function isPushed();
/**
* Declare as pushed.
*
* @return PushInterface
*/
public function pushed();
/**
* Get Adapter.
*
* @return AdapterInterface
*/
public function getAdapter();
/**
* Set Adapter.
*
* @param AdapterInterface $adapter Adapter
*
* @return PushInterface
*/
public function setAdapter(AdapterInterface $adapter);
/**
* Get Message.
*
* @return MessageInterface
*/
public function getMessage();
/**
* Set Message.
*
* @param MessageInterface $message Message
*
* @return PushInterface
*/
public function setMessage(MessageInterface $message);
/**
* Get Devices.
*
* @return DeviceCollection
*/
public function getDevices();
/**
* Set Devices.
*
* @param DeviceCollection $devices Devices
*
* @return PushInterface
*/
public function setDevices(DeviceCollection $devices);
/**
* Get PushedAt.
*
* @return DateTime
*/
public function getPushedAt();
/**
* Set PushedAt.
*
* @param DateTime $pushedAt PushedAt
*
* @return PushInterface
*/
public function setPushedAt(DateTime $pushedAt);
}

View File

@@ -0,0 +1,20 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher;
/**
* NotificationPusher.
*/
class NotificationPusher
{
const VERSION = '2.0';
}

View File

@@ -0,0 +1,97 @@
<?php
/*
* This file is part of NotificationPusher.
*
* (c) 2013 Cédric Dugat <cedric@dugat.me>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sly\NotificationPusher;
use Sly\NotificationPusher\Collection\PushCollection;
use Sly\NotificationPusher\Adapter\AdapterInterface;
use Sly\NotificationPusher\Exception\AdapterException;
/**
* PushManager.
*
* @uses \Sly\NotificationPusher\Collection\PushCollection
* @author Cédric Dugat <cedric@dugat.me>
*/
class PushManager extends PushCollection
{
const ENVIRONMENT_DEV = 'dev';
const ENVIRONMENT_PROD = 'prod';
/**
* @var string
*/
private $environment;
/**
* Constructor.
*
* @param string $environment Environment
*/
public function __construct($environment = self::ENVIRONMENT_DEV)
{
parent::__construct();
$this->environment = $environment;
}
/**
* Get environment.
*
* @return string
*/
public function getEnvironment()
{
return $this->environment;
}
/**
* Push.
*
* @return \Sly\NotificationPusher\Collection\PushCollection
*/
public function push()
{
foreach ($this as $push) {
$adapter = $push->getAdapter();
$adapter->setEnvironment($this->getEnvironment());
if ($adapter->push($push)) {
$push->pushed();
}
}
return $this;
}
/**
* Get feedback.
*
* @param \Sly\NotificationPusher\Adapter\AdapterInterface $adapter Adapter
*
* @return array
*
* @throws AdapterException When the adapter has no dedicated `getFeedback` method
*/
public function getFeedback(AdapterInterface $adapter)
{
if (false === method_exists($adapter, 'getFeedback')) {
throw new AdapterException(
sprintf(
'%s adapter has no dedicated "getFeedback" method',
(string) $adapter
)
);
}
return $adapter->getFeedback();
}
}

View File

@@ -0,0 +1,186 @@
<?php
namespace tests\units\Sly\NotificationPusher\Adapter;
use mageekguy\atoum as Units;
use Sly\NotificationPusher\Adapter\Apns as TestedModel;
use Sly\NotificationPusher\Model\Message as BaseMessage;
use Sly\NotificationPusher\Model\Device as BaseDevice;
use Sly\NotificationPusher\Collection\DeviceCollection as BaseDeviceCollection;
use ZendService\Apple\Apns\Message as BaseServiceMessage;
use ZendService\Apple\Apns\Client\Message as BaseServiceClient;
/**
* Apns.
*
* @uses atoum\test
* @author Cédric Dugat <cedric@dugat.me>
*/
class Apns extends Units\Test
{
const APNS_TOKEN_EXAMPLE = '111db24975bb6c6b63214a8d268052aa0a965cc1e32110ab06a72b19074c2222';
public function testConstruct()
{
$this
->exception(function() {
$object = new TestedModel();
})
->isInstanceOf('\Symfony\Component\OptionsResolver\Exception\MissingOptionsException')
->message
->contains('certificate')
->exception(function() {
$object = new TestedModel(array('certificate' => 'absent.pem'));
})
->isInstanceOf('\Sly\NotificationPusher\Exception\AdapterException')
->message
->contains('does not exist')
->when($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Apns', '\Mock'))
->and($object = new \Mock\Apns())
->and($object->setParameters(array('certificate' => 'test.pem', 'passPhrase' => 'test')))
->array($object->getParameters())
->isNotEmpty()
->hasSize(2)
->string($object->getParameter('certificate'))
->isEqualTo('test.pem')
;
}
public function testSupports()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Apns', '\Mock'))
->and($object = new \Mock\Apns())
->boolean($object->supports('wrongToken'))
->isFalse()
->boolean($object->supports(self::APNS_TOKEN_EXAMPLE))
->isTrue()
;
}
public function testDefaultParameters()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Apns', '\Mock'))
->and($object = new \Mock\Apns())
->array($defaultParameters = $object->getDefaultParameters())
->isNotEmpty()
->hasKey('passPhrase')
->variable($defaultParameters['passPhrase'])
->isNull()
;
}
public function testRequiredParameters()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Apns', '\Mock'))
->and($object = new \Mock\Apns())
->array($requiredParameters = $object->getRequiredParameters())
->isNotEmpty()
->contains('certificate')
;
}
public function testGetOpenedClient()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Apns', '\Mock'))
->and($object = new \Mock\Apns())
->and($this->mockGenerator()->orphanize('__construct'))
->and($this->mockGenerator()->orphanize('open'))
->and($this->mockClass('\ZendService\Apple\Apns\Client\Message', '\Mock\ZendService'))
->and($serviceClient = new \Mock\ZendService\Message())
->and($object->getMockController()->getParameters = array())
->exception(function() use($object) {
$object->getOpenedClient(new BaseServiceClient());
})
->isInstanceOf('\ZendService\Apple\Exception\InvalidArgumentException')
->message
->contains('Certificate must be a valid path to a APNS certificate')
->when($object = new TestedModel(array('certificate' => __DIR__.'/../Resources/apns-certificate.pem')))
->and($object->getOpenedClient($serviceClient))
;
}
public function testGetServiceMessageFromOrigin()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Apns', '\Mock'))
->and($object = new \Mock\Apns())
->and($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Model\Device', '\Mock'))
->and($device = new \Mock\Device())
->and($device->getMockController()->getToken = self::APNS_TOKEN_EXAMPLE)
->and($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Model\Message', '\Mock'))
->and($message = new \Mock\Message())
->and($message->getMockController()->getText = 'Test')
->object($object->getServiceMessageFromOrigin($device, $message))
->isInstanceOf('\ZendService\Apple\Apns\Message')
;
}
public function testPush()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Apns', '\Mock'))
->and($object = new \Mock\Apns())
->and($this->mockClass('\ZendService\Apple\Apns\Response\Message', '\Mock\ZendService', 'Response'))
->and($serviceResponse = new \Mock\ZendService\Response())
->and($this->mockGenerator()->orphanize('__construct'))
->and($this->mockGenerator()->orphanize('open'))
->and($this->mockGenerator()->orphanize('send'))
->and($this->mockClass('\ZendService\Apple\Apns\Client\Message', '\Mock\ZendService'))
->and($serviceClient = new \Mock\ZendService\Message())
->and($serviceClient->getMockController()->send = new $serviceResponse)
->and($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Model\Push', '\Mock'))
->and($push = new \Mock\Push())
->and($push->getMockController()->getMessage = new BaseMessage('Test'))
->and($push->getMockController()->getDevices = new BaseDeviceCollection(array(new BaseDevice(self::APNS_TOKEN_EXAMPLE))))
->and($object->getMockController()->getServiceMessageFromOrigin = new BaseServiceMessage())
->and($object->getMockController()->getOpenedClient = $serviceClient)
->object($object->push($push))
->isInstanceOf('\Sly\NotificationPusher\Collection\DeviceCollection')
->hasSize(1)
;
}
public function testFeedback()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Apns', '\Mock'))
->and($object = new \Mock\Apns())
->and($this->mockClass('\ZendService\Apple\Apns\Response\Message', '\Mock\ZendService', 'Response'))
->and($serviceResponse = new \Mock\ZendService\Response())
->and($this->mockGenerator()->orphanize('__construct'))
->and($this->mockGenerator()->orphanize('open'))
->and($this->mockGenerator()->orphanize('send'))
->and($this->mockClass('\ZendService\Apple\Apns\Client\Feedback', '\Mock\ZendService'))
->and($serviceClient = new \Mock\ZendService\Feedback())
->and($serviceClient->getMockController()->feedback = $serviceResponse)
->and($object->getMockController()->getServiceMessageFromOrigin = new BaseServiceMessage())
->and($object->getMockController()->getOpenedClient = $serviceClient)
->array($object->getFeedback())
->isEmpty()
;
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace tests\units\Sly\NotificationPusher\Adapter;
use mageekguy\atoum as Units;
use Sly\NotificationPusher\PushManager as BasePushManager;
/**
* BaseAdapter.
*
* @uses atoum\test
* @author Cédric Dugat <cedric@dugat.me>
*/
class BaseAdapter extends Units\Test
{
public function testAdapterKey()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Apns', '\Mock'))
->and($object = new \Mock\Apns())
->and($object->getMockController()->getAdapterKey = 'Apns')
->string($object->getAdapterKey())
->isEqualTo('Apns')
->string((string) $object)
->isEqualTo('Apns')
;
}
public function testEnvironment()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Apns', '\Mock'))
->and($object = new \Mock\Apns())
->when($object->setEnvironment(BasePushManager::ENVIRONMENT_DEV))
->string($object->getEnvironment())
->isEqualTo(BasePushManager::ENVIRONMENT_DEV)
->boolean($object->isDevelopmentEnvironment())
->isTrue()
->boolean($object->isProductionEnvironment())
->isFalse()
->when($object->setEnvironment(BasePushManager::ENVIRONMENT_PROD))
->string($object->getEnvironment())
->isEqualTo(BasePushManager::ENVIRONMENT_PROD)
->boolean($object->isProductionEnvironment())
->isTrue()
->boolean($object->isDevelopmentEnvironment())
->isFalse()
;
}
}

View File

@@ -0,0 +1,148 @@
<?php
namespace tests\units\Sly\NotificationPusher\Adapter;
use mageekguy\atoum as Units;
use Sly\NotificationPusher\Adapter\Gcm as TestedModel;
use Sly\NotificationPusher\Model\Message as BaseMessage;
use Sly\NotificationPusher\Model\Device as BaseDevice;
use Sly\NotificationPusher\Collection\DeviceCollection as BaseDeviceCollection;
use ZendService\Google\Gcm\Client as BaseServiceClient;
use ZendService\Google\Gcm\Message as BaseServiceMessage;
/**
* Gcm.
*
* @uses atoum\test
* @author Cédric Dugat <cedric@dugat.me>
*/
class Gcm extends Units\Test
{
const GCM_TOKEN_EXAMPLE = 'AAA91bG9ISdL94D55C69NplFlxicy0iFUFTyWh3AAdMfP9npH5r_JQFTo27xpX1jfqGf-aSe6xZAsfWRefjazJpqFt03Isanv-Fi97020EKLye0ApTkHsw_0tJJzgA2Js0NsG1jLWsiJf63YSF8ropAcRp4BSxVBBB';
public function testConstruct()
{
$this
->exception(function() {
$object = new TestedModel();
})
->isInstanceOf('\Symfony\Component\OptionsResolver\Exception\MissingOptionsException')
->message
->contains('apiKey')
->when($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Gcm', '\Mock'))
->and($object = new \Mock\Gcm())
->and($object->setParameters(array('apiKey' => 'test')))
->array($object->getParameters())
->isNotEmpty()
->hasSize(1)
->string($object->getParameter('apiKey'))
->isEqualTo('test')
;
}
public function testSupports()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Gcm', '\Mock'))
->and($object = new \Mock\Gcm())
->boolean($object->supports('*()*'))
->isFalse()
->boolean($object->supports(self::GCM_TOKEN_EXAMPLE))
->isTrue()
;
}
public function testDefaultParameters()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Gcm', '\Mock'))
->and($object = new \Mock\Gcm())
->array($defaultParameters = $object->getDefaultParameters())
->isEmpty()
;
}
public function testRequiredParameters()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Gcm', '\Mock'))
->and($object = new \Mock\Gcm())
->array($requiredParameters = $object->getRequiredParameters())
->isNotEmpty()
->contains('apiKey')
;
}
public function testGetOpenedClient()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Gcm', '\Mock'))
->and($object = new \Mock\Gcm())
->and($this->mockGenerator()->orphanize('__construct'))
->and($this->mockGenerator()->orphanize('open'))
->and($this->mockClass('\ZendService\Google\Gcm\Client', '\Mock\ZendService'))
->and($serviceClient = new \Mock\ZendService\Client())
->and($object->getMockController()->getParameters = array())
->exception(function() use($object) {
$object->getOpenedClient(new BaseServiceClient());
})
->isInstanceOf('\ZendService\Google\Exception\InvalidArgumentException')
->message
->contains('The api key must be a string and not empty')
->when($object = new TestedModel(array('apiKey' => 'test')))
->and($object->getOpenedClient($serviceClient))
;
}
public function testGetServiceMessageFromOrigin()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Gcm', '\Mock'))
->and($object = new \Mock\Gcm())
->and($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Model\Message', '\Mock'))
->and($message = new \Mock\Message())
->and($message->getMockController()->getText = 'Test')
->object($object->getServiceMessageFromOrigin(array(self::GCM_TOKEN_EXAMPLE), $message))
->isInstanceOf('\ZendService\Google\Gcm\Message')
;
}
public function testPush()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Gcm', '\Mock'))
->and($object = new \Mock\Gcm())
->and($this->mockClass('\ZendService\Google\Gcm\Response', '\Mock\ZendService'))
->and($serviceResponse = new \Mock\ZendService\Response())
->and($this->mockGenerator()->orphanize('__construct'))
->and($this->mockGenerator()->orphanize('open'))
->and($this->mockGenerator()->orphanize('send'))
->and($this->mockClass('\ZendService\Google\Gcm\Client', '\Mock\ZendService'))
->and($serviceClient = new \Mock\ZendService\Message())
->and($serviceClient->getMockController()->send = new $serviceResponse)
->and($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Model\Push', '\Mock'))
->and($push = new \Mock\Push())
->and($push->getMockController()->getMessage = new BaseMessage('Test'))
->and($push->getMockController()->getDevices = new BaseDeviceCollection(array(new BaseDevice(self::GCM_TOKEN_EXAMPLE))))
->and($object->getMockController()->getServiceMessageFromOrigin = new BaseServiceMessage())
->and($object->getMockController()->getOpenedClient = $serviceClient)
->object($object->push($push))
->isInstanceOf('\Sly\NotificationPusher\Collection\DeviceCollection')
->hasSize(1)
;
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace tests\units\Sly\NotificationPusher\Model;
use mageekguy\atoum as Units;
use Sly\NotificationPusher\Model\Message;
/**
* BaseOptionedModel.
*
* @uses atoum\test
* @author Cédric Dugat <cedric@dugat.me>
*/
class BaseOptionedModel extends Units\Test
{
public function testMethods()
{
$this->if($object = new Message('Test', array('param' => 'test')))
->boolean($object->hasOption('param'))
->isTrue()
->string($object->getOption('param'))
->isEqualTo('test')
->boolean($object->hasOption('notExist'))
->isFalse()
->variable($object->getOption('notExist'))
->isNull()
->string($object->getOption('renotExist', '12345'))
->isEqualTo('12345')
->when($object->setOptions(array('chuck' => 'norris')))
->boolean($object->hasOption('chuck'))
->isTrue()
->string($object->getOption('chuck'))
->isEqualTo('norris')
->when($object->setOption('poney', 'powerful'))
->boolean($object->hasOption('poney'))
->isTrue()
->string($object->getOption('poney'))
->isEqualTo('powerful')
->when($object->setOption('null', null))
->boolean($object->hasOption('null'))
->isTrue()
->variable($object->getOption('null'))
->isNull()
;
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace tests\units\Sly\NotificationPusher\Model;
use mageekguy\atoum as Units;
use Sly\NotificationPusher\Model\Device;
/**
* BaseParameteredModel.
*
* @uses atoum\test
* @author Cédric Dugat <cedric@dugat.me>
*/
class BaseParameteredModel extends Units\Test
{
public function testMethods()
{
$this->if($object = new Device('Test', array('param' => 'test')))
->boolean($object->hasParameter('param'))
->isTrue()
->string($object->getParameter('param'))
->isEqualTo('test')
->boolean($object->hasParameter('notExist'))
->isFalse()
->variable($object->getParameter('notExist'))
->isNull()
->string($object->getParameter('renotExist', '12345'))
->isEqualTo('12345')
->when($object->setParameters(array('chuck' => 'norris')))
->boolean($object->hasParameter('chuck'))
->isTrue()
->string($object->getParameter('chuck'))
->isEqualTo('norris')
->when($object->setParameter('poney', 'powerful'))
->boolean($object->hasParameter('poney'))
->isTrue()
->string($object->getParameter('poney'))
->isEqualTo('powerful')
->when($object->setParameter('null', null))
->boolean($object->hasParameter('null'))
->isTrue()
->variable($object->getParameter('null'))
->isNull()
;
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace tests\units\Sly\NotificationPusher\Model;
use mageekguy\atoum as Units;
use Sly\NotificationPusher\Model\Device as TestedModel;
/**
* Device.
*
* @uses atoum\test
* @author Cédric Dugat <cedric@dugat.me>
*/
class Device extends Units\Test
{
public function testConstruct()
{
$this->if($object = new TestedModel('t0k3n'))
->string($object->getToken())->isEqualTo('t0k3n')
->array($object->getParameters())->isEmpty()
;
$this->if($object = new TestedModel('t0k3n', array('param' => 'test')))
->string($object->getToken())->isEqualTo('t0k3n')
->when($object->setToken('t0k3ns3tt3d'))
->string($object->getToken())->isEqualTo('t0k3ns3tt3d')
->array($object->getParameters())
->hasKey('param')
->contains('test')
->size
->isEqualTo(1)
;
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace tests\units\Sly\NotificationPusher\Model;
use mageekguy\atoum as Units;
use Sly\NotificationPusher\Model\Message as TestedModel;
/**
* Message.
*
* @uses atoum\test
* @author Cédric Dugat <cedric@dugat.me>
*/
class Message extends Units\Test
{
public function testConstruct()
{
$this->if($object = new TestedModel('Test'))
->string($object->getText())->isEqualTo('Test')
->array($object->getOptions())->isEmpty()
;
$this->if($object = new TestedModel('Test', array('param' => 'test')))
->string($object->getText())->isEqualTo('Test')
->when($object->setText('Test 2'))
->string($object->getText())->isEqualTo('Test 2')
->array($object->getOptions())
->hasKey('param')
->contains('test')
->size
->isEqualTo(1)
;
}
}

View File

@@ -0,0 +1,165 @@
<?php
namespace tests\units\Sly\NotificationPusher\Model;
use mageekguy\atoum as Units;
use Sly\NotificationPusher\Model\Push as TestedModel;
use Sly\NotificationPusher\Model\Message as BaseMessage;
use Sly\NotificationPusher\Model\Device as BaseDevice;
use Sly\NotificationPusher\Collection\DeviceCollection as BaseDeviceCollection;
use Sly\NotificationPusher\Adapter\Apns as BaseApnsAdapter;
/**
* Push.
*
* @uses atoum\test
* @author Cédric Dugat <cedric@dugat.me>
*/
class Push extends Units\Test
{
const APNS_TOKEN_EXAMPLE = '111db24975bb6c6b63214a8d268052aa0a965cc1e32110ab06a72b19074c2222';
const GCM_TOKEN_EXAMPLE = 'AAA91bG9ISdL94D55C69NplFlxicy0iFUFTyWh3AAdMfP9npH5r_JQFTo27xpX1jfqGf-aSe6xZAsfWRefjazJpqFt03Isanv-Fi97020EKLye0ApTkHsw_0tJJzgA2Js0NsG1jLWsiJf63YSF8ropAcRp4BSxVBBB';
public function testConstructWithOneDevice()
{
$this->if($this->mockClass('\Sly\NotificationPusher\Adapter\AdapterInterface', '\Mock'))
->and($adapter = new \Mock\AdapterInterface())
->and($devices = new BaseDevice('Token1'))
->and($message = new BaseMessage('Test'))
->and($object = new TestedModel($adapter, $devices, $message))
->object($object->getDevices())
->isInstanceOf('\Sly\NotificationPusher\Collection\DeviceCollection')
->integer($object->getDevices()->count())
->isEqualTo(1)
->array($object->getOptions())
->isEmpty()
;
}
public function testConstructWithManyDevicesAndOptions()
{
$this->if($this->mockClass('\Sly\NotificationPusher\Adapter\AdapterInterface', '\Mock'))
->and($adapter = new \Mock\AdapterInterface())
->and($devices = new BaseDeviceCollection(array(new BaseDevice('Token1'), new BaseDevice('Token2'), new BaseDevice('Token3'))))
->and($message = new BaseMessage('Test'))
->and($object = new TestedModel($adapter, $devices, $message, array('param' => 'test')))
->object($object->getDevices())
->isInstanceOf('\Sly\NotificationPusher\Collection\DeviceCollection')
->integer($object->getDevices()->count())
->isEqualTo(3)
->array($object->getOptions())
->hasKey('param')
->contains('test')
->size
->isEqualTo(1)
;
}
public function testStatus()
{
$this->if($this->mockClass('\Sly\NotificationPusher\Adapter\AdapterInterface', '\Mock'))
->and($adapter = new \Mock\AdapterInterface())
->and($devices = new BaseDeviceCollection(array(new BaseDevice('Token1'), new BaseDevice('Token2'), new BaseDevice('Token3'))))
->and($message = new BaseMessage('Test'))
->and($object = new TestedModel($adapter, $devices, $message))
->string($object->getStatus())
->isEqualTo(TestedModel::STATUS_PENDING)
->boolean($object->isPushed())
->isFalse()
->when($object->pushed())
->and($dt = new \DateTime())
->string($object->getStatus())
->isEqualTo(TestedModel::STATUS_PUSHED)
->boolean($object->isPushed())
->isTrue()
->dateTime($object->getPushedAt())
->isCloneOf($dt)
->when($object->setStatus(TestedModel::STATUS_PENDING))
->string($object->getStatus())
->isEqualTo(TestedModel::STATUS_PENDING)
->boolean($object->isPushed())
->isFalse()
->when($fDt = new \DateTime('2013-01-01'))
->and($object->setPushedAt($fDt))
->dateTime($object->getPushedAt())
->isCloneOf(new \DateTime('2013-01-01'))
;
}
public function testDevicesTokensCheck()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Apns', '\Mock'))
->and($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Gcm', '\Mock'))
->and($apnsAdapter = new \mock\Apns())
->and($gcmAdapter = new \mock\Gcm())
->and($badDevice = new BaseDevice('BadToken'))
->and($message = new BaseMessage('Test'))
->exception(function () use ($apnsAdapter, $badDevice, $message) {
$object = new TestedModel($apnsAdapter, $badDevice, $message);
})
->isInstanceOf('\Sly\NotificationPusher\Exception\AdapterException')
->when($goodDevice = new BaseDevice(self::APNS_TOKEN_EXAMPLE))
->object($object = new TestedModel($apnsAdapter, $goodDevice, $message))
;
}
public function testAdapter()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Apns', '\Mock'))
->and($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Gcm', '\Mock'))
->and($apnsAdapter = new \mock\Apns())
->and($gcmAdapter = new \mock\Gcm())
->and($devices = new BaseDevice(self::APNS_TOKEN_EXAMPLE))
->and($message = new BaseMessage('Test'))
->and($object = new TestedModel($apnsAdapter, $devices, $message))
->object($object->getAdapter())
->isInstanceOf('\Sly\NotificationPusher\Adapter\Apns')
->when($object->setAdapter($gcmAdapter))
->and($object->setDevices(new BaseDeviceCollection(array(new BaseDevice(self::GCM_TOKEN_EXAMPLE)))))
->object($object->getAdapter())
->isInstanceOf('\Sly\NotificationPusher\Adapter\Gcm')
;
}
public function testMessage()
{
$this->if($this->mockClass('\Sly\NotificationPusher\Adapter\AdapterInterface', '\Mock'))
->and($adapter = new \Mock\AdapterInterface())
->and($devices = new BaseDeviceCollection(array(new BaseDevice('Token1'), new BaseDevice('Token2'), new BaseDevice('Token3'))))
->and($message = new BaseMessage('Test'))
->and($object = new TestedModel($adapter, $devices, $message))
->object($object->getMessage())
->isInstanceOf('\Sly\NotificationPusher\Model\Message')
->string($object->getMessage()->getText())
->isEqualTo('Test')
->when($object->setMessage(new BaseMessage('Test 2')))
->object($object->getMessage())
->isInstanceOf('\Sly\NotificationPusher\Model\Message')
->string($object->getMessage()->getText())
->isEqualTo('Test 2')
;
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace tests\units\Sly\NotificationPusher;
use mageekguy\atoum as Units;
use Sly\NotificationPusher\PushManager as TestedModel;
use Sly\NotificationPusher\Model\Message as BaseMessage;
use Sly\NotificationPusher\Model\Device as BaseDevice;
use Sly\NotificationPusher\Collection\DeviceCollection as BaseDeviceCollection;
/**
* PushManager.
*
* @uses atoum\test
* @author Cédric Dugat <cedric@dugat.me>
*/
class PushManager extends Units\Test
{
const APNS_TOKEN_EXAMPLE = '111db24975bb6c6b63214a8d268052aa0a965cc1e32110ab06a72b19074c2222';
public function testConstruct()
{
$this->if($object = new TestedModel())
->string($object->getEnvironment())
->isEqualTo(TestedModel::ENVIRONMENT_DEV)
->when($object = new TestedModel(TestedModel::ENVIRONMENT_PROD))
->string($object->getEnvironment())
->isEqualTo(TestedModel::ENVIRONMENT_PROD)
;
}
public function testCollection()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Model\Push', '\Mock'))
->and($push = new \Mock\Push())
->and($push->getMockController()->getMessage = new BaseMessage('Test'))
->and($push->getMockController()->getDevices = new BaseDeviceCollection(array(new BaseDevice(self::APNS_TOKEN_EXAMPLE))))
->and($object = new TestedModel())
->when($object->add($push))
->object($object)
->isInstanceOf('\Sly\NotificationPusher\Collection\PushCollection')
->hasSize(1)
;
}
public function testPush()
{
$this->if($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Adapter\Apns', '\Mock'))
->and($apnsAdapter = new \Mock\Apns())
->and($apnsAdapter->getMockController()->push = true)
->and($this->mockGenerator()->orphanize('__construct'))
->and($this->mockClass('\Sly\NotificationPusher\Model\Push', '\Mock'))
->and($push = new \Mock\Push())
->and($push->getMockController()->getMessage = new BaseMessage('Test'))
->and($push->getMockController()->getDevices = new BaseDeviceCollection(array(new BaseDevice(self::APNS_TOKEN_EXAMPLE))))
->and($push->getMockController()->getAdapter = $apnsAdapter)
->and($object = new TestedModel())
->and($object->add($push))
->object($object->push())
->isInstanceOf('\Sly\NotificationPusher\Collection\PushCollection')
->hasSize(1)
;
}
}