Quellcode durchsuchen

Merged ZF-12315
C2DM has been deprecated for GCM

git-svn-id: http://framework.zend.com/svn/framework/standard/branches/release-1.12@25009 44c647ce-9c0f-0410-b52a-842ac1e357ba

digitalstruct vor 13 Jahren
Ursprung
Commit
a4830daaf4

+ 0 - 43
demos/Zend/Mobile/Push/C2dmServer.php

@@ -1,43 +0,0 @@
-<?php
-require_once 'Zend/Mobile/Push/C2dm.php';
-require_once 'Zend/Mobile/Push/Message/C2dm.php';
-require_once 'Zend/Gdata/ClientLogin.php';
-
-try {
-    $client = Zend_Gdata_ClientLogin::getHttpClient(
-        'my@gmail.com', // REPLACE WITH YOUR GOOGLE ACCOUNT
-        'myPassword', // REPLACE WITH YOUR PASSWORD
-        Zend_Mobile_Push_C2dm::AUTH_SERVICE_NAME,
-        null,
-        'myAppName' // REPLACE WITH YOUR APP NAME
-    );
-} catch (Zend_Gdata_App_CaptchaRequiredException $cre) {
-    // manual login is required
-    echo 'URL of CAPTCHA image: ' . $cre->getCaptchaUrl() . PHP_EOL;
-    echo 'Token ID: ' . $cre->getCaptchaToken() . PHP_EOL;
-    exit(1);
-} catch (Zend_Gdata_App_AuthException $ae) {
-    echo 'Problem authenticating: ' . $ae->exception() . PHP_EOL;
-    exit(1);
-}
- 
-$message = new Zend_Mobile_Push_Message_C2dm();
-$message->setId(time());
-$message->setToken('ABCDEF0123456789');
-$message->setData(array(
-    'foo' => 'bar',
-    'bar' => 'foo',
-));
- 
-$c2dm = new Zend_Mobile_Push_C2dm();
-$c2dm->setLoginToken($client->getClientLoginToken());
- 
-try {
-    $c2dm->send($message);
-} catch (Zend_Mobile_Push_Exception_InvalidToken $e) {
-    // you would likely want to remove the token from being sent to again
-    echo $e->getMessage();
-} catch (Zend_Mobile_Push_Exception $e) {
-    // all other exceptions only require action to be sent or implementation of exponential backoff.
-    echo $e->getMessage();
-}

+ 33 - 0
demos/Zend/Mobile/Push/GcmServer.php

@@ -0,0 +1,33 @@
+<?php
+require_once 'Zend/Mobile/Push/Gcm.php';
+require_once 'Zend/Mobile/Push/Message/Gcm.php';
+
+$message = new Zend_Mobile_Push_Message_Gcm();
+$message->addToken('ABCDEF0123456789');
+$message->setData(array(
+    'foo' => 'bar',
+    'bar' => 'foo',
+));
+
+$gcm = new Zend_Mobile_Push_Gcm();
+$gcm->setApiKey('YOUR_API_KEY');
+
+try {
+    $response = $gcm->send($message);
+} catch (Zend_Mobile_Push_Exception $e) {
+    // exceptions require action or implementation of exponential backoff.
+    die($e->getMessage());
+}
+
+// handle all errors and registration_id's
+foreach ($response->getResults() as $k => $v) {
+    if (isset($v['registration_id'])) {
+        printf("%s has a new registration id of: %s\r\n", $k, $v['registration_id']);
+    }
+    if (isset($v['error'])) {
+        printf("%s had an error of: %s\r\n", $k, $v['error']);
+    }
+    if (isset($v['message_id'])) {
+        printf("%s was successfully sent the message, message id is: %s", $k, $v['message_id']);
+    }
+}

+ 2 - 2
documentation/manual/en/manual.xml.in

@@ -1557,9 +1557,9 @@
                     <xi:include href="../en/module_specs/Zend_Mobile_Push-Apns.xml" />
                 </xi:fallback>
             </xi:include>
-            <xi:include href="module_specs/Zend_Mobile_Push-C2dm.xml">
+            <xi:include href="module_specs/Zend_Mobile_Push-Gcm.xml">
                 <xi:fallback>
-                    <xi:include href="../en/module_specs/Zend_Mobile_Push-C2dm.xml" />
+                    <xi:include href="../en/module_specs/Zend_Mobile_Push-Gcm.xml" />
                 </xi:fallback>
             </xi:include>
             <xi:include href="module_specs/Zend_Mobile_Push-Mpns.xml">

+ 0 - 178
documentation/manual/en/module_specs/Zend_Mobile_Push-C2dm.xml

@@ -1,178 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Reviewed: no -->
-<sect1 id="zend.mobile.push.c2dm">
-    <title>Zend_Mobile_Push_C2dm</title>
-
-    <para>
-        <classname>Zend_Mobile_Push_C2dm</classname> provides the ability to
-        send push notifications to Android devices that contain Google Services. 
-        A message will always be constructed with
-        <classname>Zend_Mobile_Push_Message_C2dm</classname>.
-    </para>
-
-    <sect2 id="zend.mobile.push.c2dm.server">
-        <title>Pushing Messages</title>
-
-        <note>
-            <para>Prior to pushing messages; you must
-                <ulink
-                    url="http://code.google.com/android/c2dm/signup.html"> sign
-                    up for a c2dm account</ulink>.  In order to get your application
-                    to recieve push notifications, you should follow: <ulink
-                    url="http://code.google.com/android/c2dm/index.html#writing_apps">Writing
-                    Android Applications that Use C2DM</ulink>.</para>
-        </note>
-
-        <para>
-            When implementing C2DM; you have a few components that
-            you will utilize.  <classname>Zend_Mobile_Push_C2dm</classname>
-            which contains the server components and
-            <classname>Zend_Mobile_Push_Message_C2dm</classname> which contains
-            the message that you would like to send.  Each message sent must do
-            an HTTP request; so remember this when sending in large batches.
-        </para>
-
-        <para>
-            The actual implementation of the code is fairly minimal; however,
-            considerations to error handling must be taken.
-        </para>
-
-        <programlisting language="php"><![CDATA[
-try {
-    $client = Zend_Gdata_ClientLogin::getHttpClient(
-        'my@gmail.com', // REPLACE WITH YOUR GOOGLE ACCOUNT
-        'myPassword', // REPLACE WITH YOUR PASSWORD
-        Zend_Mobile_Push_C2dm::AUTH_SERVICE_NAME,
-        null,
-        'myAppName' // REPLACE WITH YOUR APP NAME
-    );
-} catch (Zend_Gdata_App_CaptchaRequiredException $cre) {
-    // manual login is required
-    echo 'URL of CAPTCHA image: ' . $cre->getCaptchaUrl() . PHP_EOL;
-    echo 'Token ID: ' . $cre->getCaptchaToken() . PHP_EOL;
-    exit(1);
-} catch (Zend_Gdata_App_AuthException $ae) {
-    echo 'Problem authenticating: ' . $ae->exception() . PHP_EOL;
-    exit(1);
-}
-
-$message = new Zend_Mobile_Push_Message_C2dm();
-$message->setId(time());
-$message->setToken('ABCDEF0123456789');
-$message->setData(array(
-    'foo' => 'bar',
-    'bar' => 'foo',
-));
-
-$c2dm = new Zend_Mobile_Push_C2dm();
-$c2dm->setLoginToken($client->getClientLoginToken());
-
-try {
-    $c2dm->send($message);
-} catch (Zend_Mobile_Push_Exception_InvalidToken $e) {
-    // you would likely want to remove the token from being sent to again
-    echo $e->getMessage();
-} catch (Zend_Mobile_Push_Exception $e) {
-    // all other exceptions only require action to be sent or implementation of exponential backoff.
-    echo $e->getMessage();
-}
-]]></programlisting>
-
-        <table id="zend.mobile.push.c2dm.server.exceptions">
-            <title>Exceptions and Remediation Techniques</title>
-            <tgroup cols="3" align="left" colsep="1" rowsep="1">
-                <thead>
-                    <row>
-                        <entry>Exception</entry>
-                        <entry>Meaning</entry>
-                        <entry>Handling</entry>
-                    </row>
-                </thead>
-                <tbody>
-                    <row>
-                        <entry>Zend_Mobile_Push_Exception</entry>
-                        <entry>These types of exceptions are more generic in nature
-                        and are thrown either from C2DM when there was an unknown exception
-                        or internally on input validation.</entry>
-                        <entry>Read the message and determine remediation steps.</entry>
-                    </row>
-                    <row>
-                        <entry>Zend_Mobile_Push_Exception_InvalidPayload</entry>
-                        <entry>Generally the payload will not throw an exception
-                        unless the size of the payload is too large or it is missing
-                        required content.</entry>
-                        <entry>Check the size of the payload is within the
-                        requirements of C2DM</entry>
-                    </row>
-                    <row>
-                        <entry>Zend_Mobile_Push_Exception_InvalidToken</entry>
-                        <entry>Any form of an invalid token will be if the token is
-                        no longer registered; you are missing a token or it is in an
-                        invalid format.</entry>
-                        <entry>You should remove the token and not attempt to send
-                        to it again.</entry>
-                    </row>
-                    <row>
-                        <entry>Zend_Mobile_Push_Exception_InvalidTopic</entry>
-                        <entry>An invalid topic simply means that the message id was
-                        too long or not an integer.</entry>
-                        <entry>Ensure that the message ID is an integer.</entry>
-                    </row>
-                    <row>
-                        <entry>Zend_Mobile_Push_Exception_DeviceQuotaExceeded</entry>
-                        <entry>You have sent too many messages to this device;
-                            you may retry again later.</entry>
-                        <entry>Grab the HTTP client and check to see if there
-                            was a retry-after header; otherwise implement
-                            <ulink
-                                url="http://en.wikipedia.org/wiki/Exponential_backoff">Exponential
-                                Backoff</ulink></entry>
-                    </row>
-                    <row>
-                        <entry>Zend_Mobile_Push_Exception_QuotaExceeded</entry>
-                        <entry>You have sent too many messages and have gone
-                            over the quota for the day; you may try again later.</entry>
-                        <entry>Grab the HTTP client and check to see if there
-                            was a retry-after header; like above implement
-                            Exponential Backoff.  Secondly; if you are
-                            continually going over your limit; you may request
-                            <ulink
-                                url="http://code.google.com/android/c2dm/quotas.html">Request
-                            a higher quota</ulink>.  See the link on the bottom of
-                            the page.</entry>
-                    </row>
-                </tbody>
-            </tgroup>
-        </table>
-    </sect2>
-
-    <sect2 id="zend.mobile.push.c2dm.message">
-
-        <title>Advanced Messages</title>
-
-        <para>
-            C2DM provides the ability for sending more advanced messages; for
-            instance the examples above show the most basic implementation of a
-            message.  <classname>Zend_Mobile_Push_Message_C2dm</classname>
-            allows you to do far more advanced messaging outlined below.
-        </para>
-
-        <sect3 id="zend.mobile.push.c2dm.message.delay-while-idle">
-
-            <title>Delay While Idle</title>
-
-            <para>
-                If included, indicates that the message should not be sent
-                immediately if the device is idle. The server will wait for the
-                device to become active, and then only the last message for each
-                collapse_key value will be sent.
-            </para>
-
-            <programlisting language="php"><![CDATA[
-    $message = new Zend_Mobile_Push_Message_C2dm();
-    $message->setDelayWhileIdle(true);
-    ]]></programlisting>
-
-        </sect3>
-    </sect2>
-</sect1>

+ 204 - 0
documentation/manual/en/module_specs/Zend_Mobile_Push-Gcm.xml

@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Reviewed: no -->
+<sect1 id="zend.mobile.push.gcm">
+    <title>Zend_Mobile_Push_Gcm</title>
+
+    <para>
+        <classname>Zend_Mobile_Push_Gcm</classname> provides the ability to
+        send push notifications to Android devices that contain Google Services. 
+        A message will always be constructed with
+        <classname>Zend_Mobile_Push_Message_Gcm</classname>.
+    </para>
+
+    <sect2 id="zend.mobile.push.gcm.server">
+        <title>Pushing Messages</title>
+
+        <note>
+            <para>Prior to pushing and receiving messages; you will need to create a Google
+                API Project and setup your Android app to listen to GCM
+                messages..  If you have not done this, follow the <ulink
+                url="http://developer.android.com/guide/google/gcm/gs.html">
+                GCM: Getting Started</ulink> document.
+            </para>
+        </note>
+
+        <para>
+            When implementing GCM; you have a few components that
+            you will utilize.  <classname>Zend_Mobile_Push_Gcm</classname>
+            which contains the server components,
+            <classname>Zend_Mobile_Push_Message_Gcm</classname> which contains
+            the message that you would like to send, and
+            <classname>Zend_Mobile_Push_Response_Gcm</classname> which contains
+            the response from GCM. Each message sent must do an HTTP request; so
+            remember this when sending in large batches.
+        </para>
+
+        <para>
+            The actual implementation of the code is fairly minimal; however,
+            considerations to error handling must be taken.
+        </para>
+
+        <programlisting language="php"><![CDATA[
+$message = new Zend_Mobile_Push_Message_Gcm();
+$message->addToken('ABCDEF0123456789');
+$message->setData(array(
+    'foo' => 'bar',
+    'bar' => 'foo',
+));
+
+$gcm = new Zend_Mobile_Push_Gcm();
+$gcm->setApiKey('YOUR_API_KEY');
+
+try {
+    $response = $gcm->send($message);
+} catch (Zend_Mobile_Push_Exception $e) {
+    // exceptions require action or implementation of exponential backoff.
+    die($e->getMessage());
+}
+
+// handle all errors and registration_id's
+foreach ($response->getResults() as $k => $v) {
+    if ($v['registration_id']) {
+        printf("%s has a new registration id of: %s\r\n", $k, $v['registration_id']);
+    }
+    if ($v['error']) {
+        printf("%s had an error of: %s\r\n", $k, $v['error']);
+    }
+    if ($v['message_id']) {
+        printf("%s was successfully sent the message, message id is: %s", $k, $v['message_id']);
+    }
+}
+]]></programlisting>
+
+        <table id="zend.mobile.push.gcm.server.exceptions">
+            <title>Exceptions and Remediation Techniques</title>
+            <tgroup cols="3" align="left" colsep="1" rowsep="1">
+                <thead>
+                    <row>
+                        <entry>Exception</entry>
+                        <entry>Meaning</entry>
+                        <entry>Handling</entry>
+                    </row>
+                </thead>
+                <tbody>
+                    <row>
+                        <entry>Zend_Mobile_Push_Exception</entry>
+                        <entry>These types of exceptions are more generic in nature
+                        and are thrown either from gcm when there was an unknown exception
+                        or internally on input validation.</entry>
+                        <entry>Read the message and determine remediation steps.</entry>
+                    </row>
+                    <row>
+                        <entry>Zend_Mobile_Push_Exception_InvalidAuthToken</entry>
+                        <entry>Your API key was likely typed in wrong or does
+                        not have rights to the GCM service.</entry>
+                        <entry>Check your project on the <ulink
+                        url="https://code.google.com/apis/console">Google APIs Console
+                        page</ulink>.</entry>
+                    </row>
+                    <row>
+                        <entry>Zend_Mobile_Push_Exception_ServerUnavailable</entry>
+                        <entry>This exception means there was either an internal
+                        server error OR that the server denied your request and
+                        you should look at the Retry-After header.</entry>
+                        <entry>Read the exception message and utilize
+                        Exponential Backoff</entry>
+                    </row>
+                    <row>
+                        <entry>Zend_Mobile_Push_Exception_InvalidPayload</entry>
+                        <entry>Generally the payload will not throw an exception
+                        unless the size of the payload is too large or the JSON
+                        is too large.</entry>
+                        <entry>Check the size of the payload is within the
+                        requirements of GCM, currently it is 4K.</entry>
+                    </row>
+                </tbody>
+            </tgroup>
+        </table>
+    </sect2>
+
+    <sect2 id="zend.mobile.push.gcm.message">
+
+        <title>Advanced Messages</title>
+
+        <para>
+            GCM provides the ability for sending more advanced messages; for
+            instance the examples above show the most basic implementation of a
+            message.  <classname>Zend_Mobile_Push_Message_Gcm</classname>
+            allows you to do far more advanced messaging outlined below.
+        </para>
+
+        <sect3 id="zend.mobile.push.gcm.message.delay-while-idle">
+
+            <title>Delay While Idle</title>
+
+            <para>
+                If included, indicates that the message should not be sent
+                immediately if the device is idle. The server will wait for the
+                device to become active, and then only the last message for each
+                collapse_key value will be sent.
+            </para>
+
+            <programlisting language="php"><![CDATA[
+    $message = new Zend_Mobile_Push_Message_Gcm();
+    $message->setDelayWhileIdle(true);
+    ]]></programlisting>
+
+        </sect3>
+
+        <sect3 id="zend.mobile.push.gcm.message.ttl">
+
+            <title>Time to Live</title>
+
+            <para>
+                You may set the time to live in seconds, by default GCM will
+                save it for 4 weeks.  Additionally if you specify a Time to
+                Live, you must also set an ID (the collapse key).  Generally it
+                is best by using the message data so that you know it is a
+                unique message.
+            </para>
+
+            <programlisting language="php"><![CDATA[
+    $message = new Zend_Mobile_Push_Message_Gcm();
+    $message->setTtl(86400);
+    $message->addData('key', 'value');
+    $message->setId(md5(json_encode($message->getData())));
+            ]]></programlisting>
+
+        </sect3>
+    </sect2>
+
+    <sect2 id="zend.mobile.push.gcm.response">
+
+        <title>Response</title>
+
+        <para>
+            GCM gives a response back that contains detail that needs to be
+            understood.  Most of the time you can just send a message but the
+            server may come back telling you any the message id, any errors and
+            potentially new registration ids.
+        </para>
+
+        <sect3 id="zend.mobile.push.gcm.response.result">
+
+            <title>Results</title>
+
+            <para>
+                The results are most commonly retrieved by calling the
+                getResults() method.  However, you may prefer to just get
+                certain results by using the getResult() method.  The getResult
+                method utilizes the constants RESULT_* correlating to message
+                id, error or registration id.
+            </para>
+
+            <para>
+                Several utility methods exist to give you a better idea of what
+                happened during your send.  Methods getSuccessCount(),
+                getFailureCount() and getCanonicalCount() let you know how many
+                where successful, how many failures and how many updates to
+                registration ids you have.
+            </para>
+
+        </sect3>
+
+</sect1>

+ 2 - 2
documentation/manual/en/module_specs/Zend_Mobile_Push-Introduction.xml

@@ -6,7 +6,7 @@
     <para>
         Zend_Mobile_Push provides the ability for sending push notifications to
         the vendor specific notification servers.  Currently this list includes
-        APNS (iTouch/iPad/iPhone), C2DM (Google Android) and MPNS (Windows Phone). 
+        APNS (iTouch/iPad/iPhone), GCM (Google Android) and MPNS (Windows Phone). 
     </para>
 
     <para>
@@ -87,7 +87,7 @@
                         <entry>(set|get)Token</entry>
                         <entry>Allows you to set or get the token or device id /
                         unique id that is for any specific device.  For APNS
-                        this is the device ID, for C2DM it is the registration
+                        this is the device ID, for GCM it is the registration
                         id and for MPNS it equates to the push url.</entry>
                     </row>
                     <row>

+ 0 - 213
library/Zend/Mobile/Push/C2dm.php

@@ -1,213 +0,0 @@
-<?php
-/**
- * Zend Framework
- *
- * LICENSE
- *
- * This source file is subject to the new BSD license that is bundled
- * with this package in the file LICENSE.txt.
- * It is also available through the world-wide-web at this URL:
- * http://framework.zend.com/license/new-bsd
- * If you did not receive a copy of the license and are unable to
- * obtain it through the world-wide-web, please send an email
- * to license@zend.com so we can send you a copy immediately.
- *
- * @category   Zend
- * @package    Zend_Mobile
- * @subpackage Zend_Mobile_Push
- * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
- * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id$
- */
-
-/** Zend_Http_Client **/
-require_once 'Zend/Http/Client.php';
-
-/** Zend_Mobile_Push_Abstract **/
-require_once 'Zend/Mobile/Push/Abstract.php';
-
-/** Zend_Mobile_Push_Message_C2dm **/
-require_once 'Zend/Mobile/Push/Message/C2dm.php';
-
-/**
- * C2DM Push
- *
- * @category   Zend
- * @package    Zend_Mobile
- * @subpackage Zend_Mobile_Push
- * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
- * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id$
- */
-class Zend_Mobile_Push_C2dm extends Zend_Mobile_Push_Abstract
-{
-
-    /**
-     * @const string Server URI
-     */
-    const SERVER_URI = 'https://android.apis.google.com/c2dm/send';
-
-    /**
-     * @const string ClientLogin auth service name
-     */
-    const AUTH_SERVICE_NAME = 'ac2dm';
-
-    /**
-     * Http Client
-     *
-     * @var Client
-     */
-    protected $_httpClient;
-
-    /**
-     * Login Token
-     *
-     * @var string
-     */
-    protected $_loginToken;
-
-    /**
-     * Get Login Token
-     *
-     * @return string
-     */
-    public function getLoginToken()
-    {
-        return $this->_loginToken;
-    }
-
-    /**
-     * Set Login Token
-     *
-     * @param  string $token
-     * @return Zend_Mobile_Push_C2dm
-     * @throws Zend_Mobile_Push_Exception
-     */
-    public function setLoginToken($token)
-    {
-        if (!is_string($token) || empty($token)) {
-            throw new Zend_Mobile_Push_Exception('The login token must be a string and not empty');
-        }
-        $this->_loginToken = $token;
-        return $this;
-    }
-
-    /**
-     * Get Http Client
-     *
-     * @return Zend_Http_Client
-     */
-    public function getHttpClient()
-    {
-        if (!$this->_httpClient) {
-            $this->_httpClient = new Zend_Http_Client();
-            $this->_httpClient->setConfig(array(
-                'strictredirects' => true,
-            ));
-        }
-        return $this->_httpClient;
-    }
-
-    /**
-     * Set Http Client
-     *
-     * @return Zend_Mobile_Push_C2dm
-     */
-    public function setHttpClient(Zend_Http_Client $client)
-    {
-        $this->_httpClient = $client;
-        return $this;
-    }
-
-    /**
-     * Send Message
-     *
-     * @param Zend_Mobile_Push_Message_C2dm $message
-     * @return boolean
-     * @throws Zend_Mobile_Push_Exception
-     */
-    public function send(Zend_Mobile_Push_Message_Abstract $message)
-    {
-        if (!$message->validate()) {
-            throw new Zend_Mobile_Push_Exception('The message is not valid.');
-        }
-
-        $this->connect();
-
-        $client = $this->getHttpClient();
-        $client->setUri(self::SERVER_URI);
-        $client->setHeaders('Authorization', 'GoogleLogin auth=' . $this->getLoginToken());
-        $client->setParameterPost('delay_while_idle', (int) $message->getDelayWhileIdle());
-        $client->setParameterPost('registration_id', $message->getToken());
-        $client->setParameterPost('collapse_key', $message->getId());
-        foreach ($message->getData() as $k => $v) {
-            $client->setParameterPost('data.' . $k, $v);
-        }
-        $response = $client->request('POST');
-        $this->close();
-
-
-        switch ($response->getStatus())
-        {
-            case 500:
-            case 503:
-                require_once 'Zend/Mobile/Push/Exception/ServerUnavailable.php';
-                throw new Zend_Mobile_Push_Exception_ServerUnavailable('The server was unavailable, check Retry-After header');
-                break;
-            case 401:
-                require_once 'Zend/Mobile/Push/Exception/InvalidAuthToken.php';
-                throw new Zend_Mobile_Push_Exception_InvalidAuthToken('The auth token is invalid');
-                break;
-            default:
-                $body = $response->getBody();
-                $body = preg_split('/=/', $body);
-                if (!isset($body[0]) || !isset($body[1])) {
-                    require_once 'Zend/Mobile/Push/Exception/ServerUnavailable.php';
-                    throw new Zend_Mobile_Push_Exception_ServerUnavailable('The server gave us an invalid response, try again later');
-                }
-                if (strtolower($body[0]) == 'error') {
-                    $err = strtolower($body[1]);
-                    switch ($err) {
-                        case 'quotaexceeded':
-                            require_once 'Zend/Mobile/Push/Exception/QuotaExceeded.php';
-                            throw new Zend_Mobile_Push_Exception_QuotaExceeded('Too many messages sent by the sender. Retry after a while.');
-                            break;
-                        case 'devicequotaexceeded':
-                            require_once 'Zend/Mobile/Push/Exception/DeviceQuotaExceeded.php';
-                            throw new Zend_Mobile_Push_Exception_DeviceQuotaExceeded('Too many messages sent by the sender to a specific device. Retry after a while.');
-                            break;
-                        case 'missingregistration':
-                            require_once 'Zend/Mobile/Push/Exception/InvalidToken.php';
-                            throw new Zend_Mobile_Push_Exception_InvalidToken('Missing token.  The message must always have a token.');
-                            break;
-                        case 'invalidregistration':
-                            require_once 'Zend/Mobile/Push/Exception/InvalidToken.php';
-                            throw new Zend_Mobile_Push_Exception_InvalidToken('Bad token.  Remove this token from being sent to again.');
-                            break;
-                        case 'mismatchsenderid':
-                            require_once 'Zend/Mobile/Push/Exception/InvalidToken.php';
-                            throw new Zend_Mobile_Push_Exception_InvalidToken('Bad token.  This token is not registered with the current login');
-                            break;
-                        case 'notregistered':
-                            require_once 'Zend/Mobile/Push/Exception/InvalidToken.php';
-                            throw new Zend_Mobile_Push_Exception_InvalidToken('Bad token.  This token is not registered.');
-                            break;
-                        case 'messagetoobig':
-                            require_once 'Zend/Mobile/Push/Exception/InvalidPayload.php';
-                            throw new Zend_Mobile_Push_Exception_InvalidPayload('The message is too big; reduce the size of the message.');
-                            break;
-                        case 'missingcollapsekey':
-                            require_once 'Zend/Mobile/Push/Exception/InvalidTopic.php';
-                            throw new Zend_Mobile_Push_Exception_InvalidTopic('The message id must be set; include one in the message.');
-                            break;
-                        default:
-                            $err = strip_tags($body[1]);
-                            throw new Zend_Mobile_Push_Exception(sprintf('An unknown error occurred: %s', $err));
-
-                    }
-                }
-                break;
-        }
-        return true;
-    }
-}

+ 172 - 0
library/Zend/Mobile/Push/Gcm.php

@@ -0,0 +1,172 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mobile
+ * @subpackage Zend_Mobile_Push
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/** Zend_Http_Client **/
+require_once 'Zend/Http/Client.php';
+
+/** Zend_Mobile_Push_Abstract **/
+require_once 'Zend/Mobile/Push/Abstract.php';
+
+/** Zend_Mobile_Push_Message_Gcm **/
+require_once 'Zend/Mobile/Push/Message/Gcm.php';
+
+/** Zend_Mobile_Push_Response_Gcm **/
+require_once 'Zend/Mobile/Push/Response/Gcm.php';
+
+/**
+ * GCM Push
+ *
+ * @category   Zend
+ * @package    Zend_Mobile
+ * @subpackage Zend_Mobile_Push
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+class Zend_Mobile_Push_Gcm extends Zend_Mobile_Push_Abstract
+{
+
+    /**
+     * @const string Server URI
+     */
+    const SERVER_URI = 'https://android.googleapis.com/gcm/send';
+
+    /**
+     * Http Client
+     *
+     * @var Client
+     */
+    protected $_httpClient;
+
+    /**
+     * API Key
+     *
+     * @var string
+     */
+    protected $_apiKey;
+
+    /**
+     * Get API Key
+     *
+     * @return string
+     */
+    public function getApiKey()
+    {
+        return $this->_apiKey;
+    }
+
+    /**
+     * Set API Key
+     *
+     * @param  string $key
+     * @return Zend_Mobile_Push_Gcm
+     * @throws Zend_Mobile_Push_Exception
+     */
+    public function setApiKey($key)
+    {
+        if (!is_string($key) || empty($key)) {
+            throw new Zend_Mobile_Push_Exception('The api key must be a string and not empty');
+        }
+        $this->_apiKey = $key;
+        return $this;
+    }
+
+    /**
+     * Get Http Client
+     *
+     * @return Zend_Http_Client
+     */
+    public function getHttpClient()
+    {
+        if (!$this->_httpClient) {
+            $this->_httpClient = new Zend_Http_Client();
+            $this->_httpClient->setConfig(array(
+                'strictredirects' => true,
+            ));
+        }
+        return $this->_httpClient;
+    }
+
+    /**
+     * Set Http Client
+     *
+     * @return Zend_Mobile_Push_Gcm
+     */
+    public function setHttpClient(Zend_Http_Client $client)
+    {
+        $this->_httpClient = $client;
+        return $this;
+    }
+
+    /**
+     * Send Message
+     *
+     * @param Zend_Mobile_Push_Message_Gcm $message
+     * @return boolean
+     * @throws Zend_Mobile_Push_Exception
+     */
+    public function send(Zend_Mobile_Push_Message_Abstract $message)
+    {
+        if (!$message->validate()) {
+            throw new Zend_Mobile_Push_Exception('The message is not valid.');
+        }
+
+        $this->connect();
+
+        $client = $this->getHttpClient();
+        $client->setUri(self::SERVER_URI);
+        $client->setHeaders('Authorization', 'key=' . $this->getApiKey());
+
+        $json = array('registration_ids' => $message->getToken());
+        if ($data = $message->getData()) {
+            $json['data'] = $data;
+        }
+        if ($id = $message->getId()) {
+            $json['id'] = $id;
+        }
+
+        $response = $client->setRawData($message->toJson(), 'application/json')
+                           ->request('POST');
+        $this->close();
+
+        switch ($response->getStatus())
+        {
+            case 500:
+                require_once 'Zend/Mobile/Push/Exception/ServerUnavailable.php';
+                throw new Zend_Mobile_Push_Exception_ServerUnavailable('The server encountered an internal error, try again');
+                break;
+            case 503:
+                require_once 'Zend/Mobile/Push/Exception/ServerUnavailable.php';
+                throw new Zend_Mobile_Push_Exception_ServerUnavailable('The server was unavailable, check Retry-After header');
+                break;
+            case 401:
+                require_once 'Zend/Mobile/Push/Exception/InvalidAuthToken.php';
+                throw new Zend_Mobile_Push_Exception_InvalidAuthToken('There was an error authenticating the sender account');
+                break;
+            case 400:
+                require_once 'Zend/Mobile/Push/Exception/InvalidPayload.php';
+                throw new Zend_Mobile_Push_Exception_InvalidPayload('The request could not be parsed as JSON or contains invalid fields');
+                break;
+        }
+        return new Zend_Mobile_Push_Response_Gcm($response->getBody(), $message);
+    }
+}

+ 5 - 4
library/Zend/Mobile/Push/Message/Abstract.php

@@ -30,8 +30,8 @@ require_once 'Zend/Mobile/Push/Message/Exception.php';
  * Message Abstract
  *
  * @category   Zend
- * @package    Zend\Mobile
- * @subpackage Zend\Mobile\Push\Message
+ * @package    Zend_Mobile
+ * @subpackage Zend_Mobile_Push_Message
  * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  * @version    $Id$
@@ -65,7 +65,8 @@ abstract class Zend_Mobile_Push_Message_Abstract implements Zend_Mobile_Push_Mes
     /**
      * Set Token
      *
-     * @return MessageAbstract
+     * @param  string $token
+     * @return Zend_Mobile_Push_Message_Abstract
      */
     public function setToken($token)
     {
@@ -90,7 +91,7 @@ abstract class Zend_Mobile_Push_Message_Abstract implements Zend_Mobile_Push_Mes
      * Set Message ID
      *
      * @param scalar $id
-     * @return MessageAbstract
+     * @return Zend_Mobile_Push_Message_Abstract
      * @throws Exception
      */
     public function setId($id)

+ 0 - 150
library/Zend/Mobile/Push/Message/C2dm.php

@@ -1,150 +0,0 @@
-<?php
-/**
- * Zend Framework
- *
- * LICENSE
- *
- * This source file is subject to the new BSD license that is bundled
- * with this package in the file LICENSE.txt.
- * It is also available through the world-wide-web at this URL:
- * http://framework.zend.com/license/new-bsd
- * If you did not receive a copy of the license and are unable to
- * obtain it through the world-wide-web, please send an email
- * to license@zend.com so we can send you a copy immediately.
- *
- * @category   Zend
- * @package    Zend_Mobile
- * @subpackage Zend_Mobile_Push
- * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
- * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id$
- */
-
-/** Zend_Mobile_Push_Message_Abstract **/
-require_once 'Zend/Mobile/Push/Message/Abstract.php';
-
-/**
- * C2dm Message
- *
- * @category   Zend
- * @package    Zend_Mobile
- * @subpackage Zend_Mobile_Push
- * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
- * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id$
- */
-class Zend_Mobile_Push_Message_C2dm extends Zend_Mobile_Push_Message_Abstract
-{
-    /**
-     * Data key value pairs
-     * 
-     * @var array
-     */
-    protected $_data = array();
-
-    /**
-     * Delay While Idle
-     *
-     * @var boolean
-     */
-    protected $_delay = false;
-
-    /**
-     * Add Data
-     *
-     * @param string $key
-     * @param string $value
-     * @return Zend_Mobile_Push_Message_C2dm
-     * @throws Zend_Mobile_Push_Message_Exception
-     */
-    public function addData($key, $value)
-    {
-        if (!is_string($key)) {
-            throw new Zend_Mobile_Push_Message_Exception('$key is not a string');
-        }
-        if (!is_scalar($value)) {
-            throw new Zend_Mobile_Push_Message_Exception('$value is not a string');
-        }
-        $this->_data[$key] = $value;
-        return $this;
-    }
-
-    /**
-     * Set Data
-     *
-     * @param array $data
-     * @return Zend_Mobile_Push_Message_C2dm
-     * @throws Zend_Mobile_Push_Message_Exception
-     */
-    public function setData(array $data)
-    {
-        $this->clearData();
-        foreach ($data as $k => $v) {
-            $this->addData($k, $v);
-        }
-        return $this;
-    }
-
-    /**
-     * Clear Data
-     *
-     * @return Zend_Mobile_Push_Message_C2dm
-     */
-    public function clearData()
-    {
-        $this->_data = array();
-    }
-
-    /**
-     * Get Data
-     *
-     * @return array
-     */
-    public function getData()
-    {
-        return $this->_data;
-    }
-
-    /**
-     * Set Delay While Idle
-     *
-     * @param boolean $delay
-     * @return Zend_Mobile_Push_Message_C2dm
-     * @throws Zend_Mobile_Push_Message_Exception
-     */
-    public function setDelayWhileIdle($delay)
-    {
-        if (!is_bool($delay)) {
-            throw new Zend_Mobile_Push_Message_Exception('$delay must be boolean');
-        }
-        $this->_delay = $delay;
-        return $this;
-    }
-
-    /**
-     * Get Delay While Idle
-     *
-     * @return boolean
-     */
-    public function getDelayWhileIdle()
-    {
-        return $this->_delay;
-    }
-
-    /**
-     * Validate this is a proper C2dm message
-     * Does not validate size.
-     *
-     * @return boolean
-     */
-    public function validate()
-    {
-        if (!is_string($this->_token) || strlen($this->_token) === 0) {
-            return false;
-        }
-        if (!is_scalar($this->_id) || strlen($this->_id) === 0) {
-            return false;
-        }
-        return true;
-    }
-}

+ 273 - 0
library/Zend/Mobile/Push/Message/Gcm.php

@@ -0,0 +1,273 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mobile
+ * @subpackage Zend_Mobile_Push
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/** Zend_Mobile_Push_Message_Abstract **/
+require_once 'Zend/Mobile/Push/Message/Abstract.php';
+
+/**
+ * Gcm Message
+ *
+ * @category   Zend
+ * @package    Zend_Mobile
+ * @subpackage Zend_Mobile_Push
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+class Zend_Mobile_Push_Message_Gcm extends Zend_Mobile_Push_Message_Abstract
+{
+
+    /**
+     * Tokens
+     *
+     * @var array
+     */
+    protected $_token = array();
+
+    /**
+     * Data key value pairs
+     * 
+     * @var array
+     */
+    protected $_data = array();
+
+    /**
+     * Delay while idle
+     *
+     * @var boolean
+     */
+    protected $_delay = false;
+
+    /**
+     * Time to live in seconds
+     * 
+     * @var int
+     */
+    protected $_ttl = 0;
+
+    /**
+     * Add a Token
+     *
+     * @param  string $token
+     * @return Zend_Mobile_Push_Message_Gcm
+     * @throws Zend_Mobile_Push_Message_Exception
+     */
+    public function addToken($token)
+    {
+        if (!is_string($token)) {
+            throw new Zend_Mobile_Push_Message_Exception('$token must be a string');
+        }
+        if (!in_array($token, $this->_token)) {
+           $this->_token[] = $token;
+        }
+        return $this;
+    }
+
+    /**
+     * Set Token
+     *
+     * @param  string|array $token
+     * @return Zend_Mobile_Push_Message_Gcm
+     * @throws Zend_Mobile_Push_Message_Exception
+     */
+    public function setToken($token)
+    {
+        $this->clearToken();
+        if (is_string($token)) {
+            $this->addToken($token);
+        } else if (is_array($token)) {
+            foreach ($token as $t) {
+                $this->addToken($t);
+            }
+        }
+        return $this;
+    }
+
+    /**
+     * Clear Tokens
+     *
+     * @return Zend_Mobile_Push_Message_Gcm
+     */
+    public function clearToken()
+    {
+        $this->_token = array();
+        return $this;
+    }
+
+
+    /**
+     * Add Data
+     *
+     * @param  string $key
+     * @param  string $value
+     * @return Zend_Mobile_Push_Message_Gcm
+     * @throws Zend_Mobile_Push_Message_Exception
+     */
+    public function addData($key, $value)
+    {
+        if (!is_string($key)) {
+            throw new Zend_Mobile_Push_Message_Exception('$key is not a string');
+        }
+        if (!is_scalar($value)) {
+            throw new Zend_Mobile_Push_Message_Exception('$value is not a string');
+        }
+        $this->_data[$key] = $value;
+        return $this;
+    }
+
+    /**
+     * Set Data
+     *
+     * @param array $data
+     * @return Zend_Mobile_Push_Message_Gcm
+     * @throws Zend_Mobile_Push_Message_Exception
+     */
+    public function setData(array $data)
+    {
+        $this->clearData();
+        foreach ($data as $k => $v) {
+            $this->addData($k, $v);
+        }
+        return $this;
+    }
+
+    /**
+     * Clear Data
+     *
+     * @return Zend_Mobile_Push_Message_Gcm
+     */
+    public function clearData()
+    {
+        $this->_data = array();
+        return $this;
+    }
+
+    /**
+     * Get Data
+     *
+     * @return array
+     */
+    public function getData()
+    {
+        return $this->_data;
+    }
+
+    /**
+     * Set Delay While Idle
+     *
+     * @param boolean $delay
+     * @return Zend_Mobile_Push_Message_Gcm
+     * @throws Zend_Mobile_Push_Message_Exception
+     */
+    public function setDelayWhileIdle($delay)
+    {
+        if (!is_bool($delay)) {
+            throw new Zend_Mobile_Push_Message_Exception('$delay must be boolean');
+        }
+        $this->_delay = $delay;
+        return $this;
+    }
+
+    /**
+     * Get Delay While Idle
+     *
+     * @return boolean
+     */
+    public function getDelayWhileIdle()
+    {
+        return $this->_delay;
+    }
+
+    /**
+     * Set time to live
+     * If $secs is set to 0 it will be handled as
+     * not being set.
+     *
+     * @param  int $secs
+     * @return Zend_Mobile_Push_Message_Gcm
+     */
+    public function setTtl($secs)
+    {
+        if (!is_numeric($secs)) {
+            throw new Zend_Mobile_Push_Message_Exception('$secs must be numeric');
+        }
+        $this->_ttl = (int) $secs;
+        return $this;
+    }
+
+    /**
+     * Get time to live
+     *
+     * @return int
+     */
+    public function getTtl()
+    {
+        return $this->_ttl;
+    }
+
+    /**
+     * Validate this is a proper Gcm message
+     * Does not validate size.
+     *
+     * @return boolean
+     */
+    public function validate()
+    {
+        if (!is_array($this->_token) || empty($this->_token)) {
+            return false;
+        }
+        if ($this->_ttl > 0 &&
+            (!is_scalar($this->_id) ||
+            strlen($this->_id) === 0)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * To Json utility method
+     * Takes the data and properly assigns it to
+     * a json encoded array to match the Gcm format.
+     *
+     * @return string
+     */
+    public function toJson()
+    {
+        $json = array();
+        if ($this->_token) {
+            $json['registration_ids'] = $this->_token;
+        }
+        if ($this->_id) {
+            $json['collapse_key'] = $this->_id;
+        }
+        if ($this->_data) {
+            $json['data'] = $this->_data;
+        }
+        if ($this->_delay) {
+            $json['delay_while_idle'] = $this->_delay;
+        }
+        if ($this->_ttl) {
+            $json['time_to_live'] = $this->_ttl;
+        }
+        return json_encode($json);
+    }
+}

+ 1 - 1
library/Zend/Mobile/Push/Mpns.php

@@ -67,7 +67,7 @@ class Zend_Mobile_Push_Mpns extends Zend_Mobile_Push_Abstract
     /**
      * Set Http Client
      *
-     * @return Zend_Mobile_Push_C2dm
+     * @return Zend_Mobile_Push_Mpns
      */
     public function setHttpClient(Zend_Http_Client $client)
     {

+ 242 - 0
library/Zend/Mobile/Push/Response/Gcm.php

@@ -0,0 +1,242 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mobile
+ * @subpackage Zend_Mobile_Push
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * Gcm Response
+ *
+ * @category   Zend
+ * @package    Zend_Mobile
+ * @subpackage Zend_Mobile_Push
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+class Zend_Mobile_Push_Response_Gcm
+{
+
+    const RESULT_MESSAGE_ID = 'message_id';
+    const RESULT_ERROR = 'error';
+    const RESULT_CANONICAL = 'registration_id';
+
+    /**
+     * Multicast ID
+     * @var int
+     */
+    protected $_id;
+
+    /**
+     * Success Count
+     * @var int
+     */
+    protected $_successCnt;
+
+    /**
+     * Failure Count
+     * @var int
+     */
+    protected $_failureCnt;
+
+    /**
+     * Canonical registration id count
+     * @var int
+     */
+    protected $_canonicalCnt;
+
+    /**
+     * Message
+     * @var Zend_Mobile_Push_Message_Gcm
+     */
+    protected $_message;
+
+    /**
+     * Results
+     * @var array
+     */
+    protected $_results;
+
+    /**
+     * Raw Response
+     * @var array
+     */
+    protected $_response;
+
+    /**
+     * Constructor
+     *
+     * @param string $responseString JSON encoded response
+     * @param Zend_Mobile_Push_Message_Gcm $message
+     * @return Zend_Mobile_Push_Response_Gcm
+     * @throws Zend_Mobile_Push_Exception_ServerUnavailable
+     */
+    public function __construct($responseString = null, Zend_Mobile_Push_Message_Gcm $message = null)
+    {
+        if ($responseString) {
+            if (!$response = json_decode($responseString, true)) {
+                require_once 'Zend/Mobile/Push/Exception/ServerUnavailable.php';
+                throw new Zend_Mobile_Push_Exception_ServerUnavailable('The server gave us an invalid response, try again later');
+            }
+            $this->setResponse($response);
+        }
+
+        if ($message) {
+            $this->setMessage($message);
+        }
+
+    }
+
+    /**
+     * Get Message
+     *
+     * @return Zend_Mobile_Push_Message_Gcm
+     */
+    public function getMessage()
+    {
+        return $this->_message;
+    }
+
+    /**
+     * Set Message
+     *
+     * @param Zend_Mobile_Push_Message_Gcm $message
+     * @return Zend_Mobile_Push_Response_Gcm
+     */
+    public function setMessage(Zend_Mobile_Push_Message_Gcm $message)
+    {
+        $this->_message = $message;
+        return $this;
+    }
+
+    /**
+     * Get Response
+     *
+     * @return array
+     */
+    public function getResponse()
+    {
+        return $this->_response;
+    }
+
+    /**
+     * Set Response
+     *
+     * @param array $response
+     * @return Zend_Mobile_Push_Response_Gcm
+     */
+    public function setResponse(array $response)
+    {
+        if (!isset($response['results']) ||
+            !isset($response['success']) ||
+            !isset($response['failure']) ||
+            !isset($response['canonical_ids']) ||
+            !isset($response['multicast_id'])) {
+            throw new Zend_Mobile_Push_Exception('Response did not contain the proper fields');
+        }
+        $this->_response = $response;
+        $this->_results = $response['results'];
+        $this->_successCnt = (int) $response['success'];
+        $this->_failureCnt = (int) $response['failure'];
+        $this->_canonicalCnt = (int) $response['canonical_ids'];
+        $this->_id = (int) $response['multicast_id'];
+        return $this;
+    }
+
+    /**
+     * Get Success Count
+     *
+     * @return int
+     */
+    public function getSuccessCount()
+    {
+        return $this->_successCnt;
+    }
+
+    /**
+     * Get Failure Count
+     *
+     * @return int
+     */
+    public function getFailureCount()
+    {
+        return $this->_failureCnt;
+    }
+
+    /**
+     * Get Canonical Count
+     *
+     * @return int
+     */
+    public function getCanonicalCount()
+    {
+        return $this->_canonicalCnt;
+    }
+
+    /**
+     * Get Results
+     *
+     * @return array multi dimensional array of:
+     *         NOTE: key is registration_id if the message is passed.
+     *         'registration_id' => array( 
+     *             'message_id' => 'id',
+     *             'error' => 'error',
+     *             'registration_id' => 'id'
+     *          )
+     */
+    public function getResults()
+    {
+        return $this->_correlate();
+    }
+
+    /**
+     * Get Singular Result
+     *
+     * @param  int   $flag one of the RESULT_* flags
+     * @return array singular array with keys being registration id
+     *               value is the type of result
+     */
+    public function getResult($flag)
+    {
+        $ret = array();
+        foreach ($this->_correlate() as $k => $v) {
+            if (isset($v[$flag])) {
+                $ret[$k] = $v[$flag];
+            }
+        }
+        return $ret;
+    }
+
+    /**
+     * Correlate Message and Result
+     *
+     * @return array
+     */
+    protected function _correlate()
+    {
+        $results = $this->_results;
+        if ($this->_message && $results) {
+            $tokens = $this->_message->getToken();
+            while($token = array_shift($tokens)) {
+                $results[$token] = array_shift($results);
+            }
+        }
+        return $results;
+    }
+}

+ 3 - 2
tests/Zend/Mobile/Push/AllTests.php

@@ -25,9 +25,10 @@ if (!defined('PHPUnit_MAIN_METHOD')) {
 }
 
 require_once 'Zend/Mobile/Push/Message/AllTests.php';
+require_once 'Zend/Mobile/Push/Response/AllTests.php';
 require_once 'Zend/Mobile/Push/AbstractTest.php';
 require_once 'Zend/Mobile/Push/ApnsTest.php';
-require_once 'Zend/Mobile/Push/C2dmTest.php';
+require_once 'Zend/Mobile/Push/GcmTest.php';
 require_once 'Zend/Mobile/Push/MpnsTest.php';
 
 /**
@@ -53,7 +54,7 @@ class Zend_Mobile_Push_AllTests
          
         $suite->addTestSuite('Zend_Mobile_Push_AbstractTest');
         $suite->addTestSuite('Zend_Mobile_Push_ApnsTest');
-        $suite->addTestSuite('Zend_Mobile_Push_C2dmTest');
+        $suite->addTestSuite('Zend_Mobile_Push_GcmTest');
         $suite->addTestSuite('Zend_Mobile_Push_MpnsTest');
 
         return $suite;

+ 0 - 226
tests/Zend/Mobile/Push/C2dmTest.php

@@ -1,226 +0,0 @@
-<?php
-/**
- * Zend Framework
- *
- * LICENSE
- *
- * This source file is subject to the new BSD license that is bundled
- * with this package in the file LICENSE.txt.
- * It is also available through the world-wide-web at this URL:
- * http://framework.zend.com/license/new-bsd
- * If you did not receive a copy of the license and are unable to
- * obtain it through the world-wide-web, please send an email
- * to license@zend.com so we can send you a copy immediately.
- *
- * @category   Zend
- * @package    Zend_Mobile
- * @subpackage Push
- * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
- * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @version    $Id $
- */
-
-require_once 'Zend/Mobile/Push/C2dm.php';
-require_once 'Zend/Http/Client.php';
-require_once 'Zend/Http/Client/Adapter/Test.php';
-
-/**
- * @category   Zend
- * @package    Zend_Mobile
- * @subpackage Push
- * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
- * @license    http://framework.zend.com/license/new-bsd     New BSD License
- * @group      Zend_Mobile
- * @group      Zend_Mobile_Push
- * @group      Zend_Mobile_Push_C2dm
- */
-class Zend_Mobile_Push_C2dmTest extends PHPUnit_Framework_TestCase
-{
-
-    public function setUp()
-    {
-        $this->adapter = new Zend_Http_Client_Adapter_Test();
-        $this->client = new Zend_Http_Client();
-        $this->client->setAdapter($this->adapter);
-        $this->c2dm = new Zend_Mobile_Push_C2dm();
-        $this->c2dm->setLoginToken('testing');
-        $this->c2dm->setHttpClient($this->client);
-        $this->message = new Zend_Mobile_Push_Message_C2dm();
-        $this->message->setId('testing');
-        $this->message->setToken('testing');
-        $this->message->addData('testKey', 'testValue');
-    }
-
-    /**
-     * @expectedException Zend_Mobile_Push_Exception
-     */
-    public function testSetLoginTokenThrowsExceptionOnNonString()
-    {
-        $this->c2dm->setLoginToken(array());
-    }
-
-    public function testSetLoginToken()
-    {
-        $loginToken = 'a-login-token';
-        $this->c2dm->setLoginToken($loginToken);
-        $this->assertEquals($loginToken, $this->c2dm->getLoginToken());
-    }
-
-    public function testGetHttpClientReturnsDefault()
-    {
-        $c2dm = new Zend_Mobile_Push_C2dm();
-        $this->assertEquals('Zend_Http_Client', get_class($c2dm->getHttpClient()));
-        $this->assertTrue($c2dm->getHttpClient() instanceof Zend_Http_Client);
-    }
-
-    public function testSetHttpClient()
-    {
-        $client = new Zend_Http_Client();
-        $this->c2dm->setHttpClient($client);
-        $this->assertEquals($client, $this->c2dm->getHttpClient());
-    }
-
-    /**
-     * @expectedException Zend_Mobile_Push_Exception
-     */
-    public function testSendThrowsExceptionWithNonValidMessage()
-    {
-        $msg = new Zend_Mobile_Push_Message_C2dm();
-        $this->c2dm->send($msg);
-    }
-
-    /**
-     * @expectedException Zend_Mobile_Push_Exception_ServerUnavailable
-     */
-    public function testSendThrowsExceptionWhenServerUnavailable()
-    {
-        $this->adapter->setResponse('HTTP/1.1 500 Internal Server Error' . "\r\n\r\n");
-        $this->c2dm->send($this->message);
-    }
-
-    /**
-     * @expectedException Zend_Mobile_Push_Exception_InvalidAuthToken
-     */
-    public function testSendThrowsExceptionWhenInvalidAuthToken()
-    {
-        $this->adapter->setResponse('HTTP/1.1 401 Unauthorized' . "\r\n\r\n");
-        $this->c2dm->send($this->message);
-    }
-
-    /**
-     * @expectedException Zend_Mobile_Push_Exception_QuotaExceeded
-     */
-    public function testSendThrowsExceptionWhenQuotaExceeded()
-    {
-        $this->adapter->setResponse(
-            'HTTP/1.1 200 OK' . "\r\n" .
-            'Context-Type: text/html' . "\r\n\r\n" .
-            'Error=QuotaExceeded'
-        );
-        $this->c2dm->send($this->message);
-    }
-
-    /**
-     * @expectedException Zend_Mobile_Push_Exception_DeviceQuotaExceeded
-     */
-    public function testSendThrowsExceptionWhenDeviceQuotaExceeded()
-    {
-        $this->adapter->setResponse(
-            'HTTP/1.1 200 OK' . "\r\n" .
-            'Context-Type: text/html' . "\r\n\r\n" .
-            'Error=DeviceQuotaExceeded'
-        );
-        $this->c2dm->send($this->message);
-    }
-
-    /**
-     * @expectedException Zend_Mobile_Push_Exception_InvalidToken
-     */
-    public function testSendThrowsExceptionWhenMissingRegistration()
-    {
-        $this->adapter->setResponse(
-            'HTTP/1.1 200 OK' . "\r\n" .
-            'Context-Type: text/html' . "\r\n\r\n" .
-            'Error=MissingRegistration'
-        );
-        $this->c2dm->send($this->message);
-    }
-
-    /**
-     * @expectedException Zend_Mobile_Push_Exception_InvalidToken
-     */
-    public function testSendThrowsExceptionWhenInvalidRegistration()
-    {
-        $this->adapter->setResponse(
-            'HTTP/1.1 200 OK' . "\r\n" .
-            'Context-Type: text/html' . "\r\n\r\n" .
-            'Error=InvalidRegistration'
-        );
-        $this->c2dm->send($this->message);
-    }
-
-    /**
-     * @expectedException Zend_Mobile_Push_Exception_InvalidToken
-     */
-    public function testSendThrowsExceptionWhenMismatchSenderId()
-    {
-        $this->adapter->setResponse(
-            'HTTP/1.1 200 OK' . "\r\n" .
-            'Context-Type: text/html' . "\r\n\r\n" .
-            'Error=MismatchSenderId'
-        );
-        $this->c2dm->send($this->message);
-    }
-
-    /**
-     * @expectedException Zend_Mobile_Push_Exception_InvalidToken
-     */
-    public function testSendThrowsExceptionWhenNotRegistered()
-    {
-        $this->adapter->setResponse(
-            'HTTP/1.1 200 OK' . "\r\n" .
-            'Context-Type: text/html' . "\r\n\r\n" .
-            'Error=NotRegistered'
-        );
-        $this->c2dm->send($this->message);
-    }
-
-    /**
-     * @expectedException Zend_Mobile_Push_Exception_InvalidPayload
-     */
-    public function testSendThrowsExceptionWhenMessageTooBig()
-    {
-        $this->adapter->setResponse(
-            'HTTP/1.1 200 OK' . "\r\n" .
-            'Context-Type: text/html' . "\r\n\r\n" . 
-            'Error=MessageTooBig'
-        );
-        $this->c2dm->send($this->message);
-    }
-
-    /**
-     * @expectedException Zend_Mobile_Push_Exception_InvalidTopic
-     */
-    public function testSendThrowsExceptionWhenMissingCollapseKey()
-    {
-        $this->adapter->setResponse(
-            'HTTP/1.1 200 OK' . "\r\n" .
-            'Context-Type: text/html' . "\r\n\r\n" .
-            'Error=MissingCollapseKey'
-        );
-        $this->c2dm->send($this->message);
-    }
-
-    /**
-     * @expectedException Zend_Mobile_Push_Exception
-     */
-    public function testSendThrowsExceptionWhenUnknownError()
-    {
-        $this->adapter->setResponse(
-            'HTTP/1.1 200 OK' . "\r\n" .
-            'Context-Type: text/html' . "\r\n\r\n" .
-            'Error=somethinghappened'
-        );
-        $this->c2dm->send($this->message);
-    }
-}

+ 241 - 0
tests/Zend/Mobile/Push/GcmTest.php

@@ -0,0 +1,241 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mobile
+ * @subpackage Push
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id $
+ */
+
+require_once 'Zend/Mobile/Push/Gcm.php';
+require_once 'Zend/Http/Client.php';
+require_once 'Zend/Http/Client/Adapter/Test.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Mobile
+ * @subpackage Push
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @group      Zend_Mobile
+ * @group      Zend_Mobile_Push
+ * @group      Zend_Mobile_Push_Gcm
+ */
+class Zend_Mobile_Push_gcmTest extends PHPUnit_Framework_TestCase
+{
+
+    protected function _createJSONResponse($id, $success, $failure, $ids, $results)
+    {
+         return json_encode(array(
+            'multicast_id' => $id,
+            'success' => $success,
+            'failure' => $failure,
+            'canonical_ids' => $ids,
+            'results' => $results
+        ));
+    }
+
+    public function setUp()
+    {
+        $this->adapter = new Zend_Http_Client_Adapter_Test();
+        $this->client = new Zend_Http_Client();
+        $this->client->setAdapter($this->adapter);
+        $this->gcm = new Zend_Mobile_Push_Gcm();
+        $this->gcm->setApiKey('testing');
+        $this->gcm->setHttpClient($this->client);
+        $this->message = new Zend_Mobile_Push_Message_Gcm();
+        $this->message->addToken('testing');
+        $this->message->addData('testKey', 'testValue');
+    }
+
+    /**
+     * @expectedException Zend_Mobile_Push_Exception
+     */
+    public function testSetApiKeyThrowsExceptionOnNonString()
+    {
+        $this->gcm->setApiKey(array());
+    }
+
+    public function testSetApiKey()
+    {
+        $key = 'a-login-token';
+        $this->gcm->setApiKey($key);
+        $this->assertEquals($key, $this->gcm->getApiKey());
+    }
+
+    public function testGetHttpClientReturnsDefault()
+    {
+        $gcm = new Zend_Mobile_Push_gcm();
+        $this->assertEquals('Zend_Http_Client', get_class($gcm->getHttpClient()));
+        $this->assertTrue($gcm->getHttpClient() instanceof Zend_Http_Client);
+    }
+
+    public function testSetHttpClient()
+    {
+        $client = new Zend_Http_Client();
+        $this->gcm->setHttpClient($client);
+        $this->assertEquals($client, $this->gcm->getHttpClient());
+    }
+
+    /**
+     * @expectedException Zend_Mobile_Push_Exception
+     */
+    public function testSendThrowsExceptionWithNonValidMessage()
+    {
+        $msg = new Zend_Mobile_Push_Message_Gcm();
+        $this->gcm->send($msg);
+    }
+
+    /**
+     * @expectedException Zend_Mobile_Push_Exception
+     */
+    public function testSendThrowsExceptionWithTtlNoId()
+    {
+        $msg = $this->message;
+        $msg->setTtl(300);
+        $this->gcm->send($msg);
+    }
+
+    /**
+     * @expectedException Zend_Mobile_Push_Exception_ServerUnavailable
+     */
+    public function testSendThrowsExceptionWhenServerUnavailable()
+    {
+        $this->adapter->setResponse('HTTP/1.1 500 Internal Server Error' . "\r\n\r\n");
+        $this->gcm->send($this->message);
+    }
+
+    /**
+     * @expectedException Zend_Mobile_Push_Exception_InvalidAuthToken
+     */
+    public function testSendThrowsExceptionWhenInvalidAuthToken()
+    {
+        $this->adapter->setResponse('HTTP/1.1 401 Unauthorized' . "\r\n\r\n");
+        $this->gcm->send($this->message);
+    }
+
+    /**
+     * @expectedException Zend_Mobile_Push_Exception_InvalidPayload
+     */
+    public function testSendThrowsExceptionWhenInvalidPayload()
+    {
+        $this->adapter->setResponse('HTTP/1.1 400 Bad Request' . "\r\n\r\n");
+        $this->gcm->send($this->message);
+    }
+
+    public function testSendResultInvalidRegistrationId()
+    {
+        $body = $this->_createJSONResponse(101, 0, 1, 0, array(array('error' => 'InvalidRegistration')));
+        $this->adapter->setResponse(
+            'HTTP/1.1 200 OK' . "\r\n" .
+            'Context-Type: text/html' . "\r\n\r\n" .
+            $body
+        );
+        $response = $this->gcm->send($this->message);
+        $result = $response->getResults();
+        $result = array_shift($result);
+        $this->assertEquals('InvalidRegistration', $result['error']);
+        $this->assertEquals(0, $response->getSuccessCount());
+        $this->assertEquals(0, $response->getCanonicalCount());
+        $this->assertEquals(1, $response->getFailureCount());
+    }
+
+    public function testSendResultMismatchSenderId()
+    {
+        $body = $this->_createJSONResponse(101, 0, 1, 0, array(array('error' => 'MismatchSenderId')));
+        $this->adapter->setResponse(
+            'HTTP/1.1 200 OK' . "\r\n" .
+            'Context-Type: text/html' . "\r\n\r\n" .
+            $body
+        );
+        $response = $this->gcm->send($this->message);
+        $result = $response->getResults();
+        $result = array_shift($result);
+        $this->assertEquals('MismatchSenderId', $result['error']);
+        $this->assertEquals(0, $response->getSuccessCount());
+        $this->assertEquals(0, $response->getCanonicalCount());
+        $this->assertEquals(1, $response->getFailureCount());
+    }
+
+    public function testSendResultNotRegistered()
+    {
+        $body = $this->_createJSONResponse(101, 0, 1, 0, array(array('error' => 'NotRegistered')));
+        $this->adapter->setResponse(
+            'HTTP/1.1 200 OK' . "\r\n" .
+            'Context-Type: text/html' . "\r\n\r\n" .
+            $body
+        );
+        $response = $this->gcm->send($this->message);
+        $result = $response->getResults();
+        $result = array_shift($result);
+        $this->assertEquals('NotRegistered', $result['error']);
+        $this->assertEquals(0, $response->getSuccessCount());
+        $this->assertEquals(0, $response->getCanonicalCount());
+        $this->assertEquals(1, $response->getFailureCount());
+    }
+
+    public function testSendResultMessageTooBig()
+    {
+        $body = $this->_createJSONResponse(101, 0, 1, 0, array(array('error' => 'MessageTooBig')));
+        $this->adapter->setResponse(
+            'HTTP/1.1 200 OK' . "\r\n" .
+            'Context-Type: text/html' . "\r\n\r\n" .
+            $body
+        );
+        $response = $this->gcm->send($this->message);
+        $result = $response->getResults();
+        $result = array_shift($result);
+        $this->assertEquals('MessageTooBig', $result['error']);
+        $this->assertEquals(0, $response->getSuccessCount());
+        $this->assertEquals(0, $response->getCanonicalCount());
+        $this->assertEquals(1, $response->getFailureCount());
+    }
+
+    public function testSendResultSuccessful()
+    {
+        $body = $this->_createJSONResponse(101, 1, 0, 0, array(array('message_id' => '1:2342')));
+        $this->adapter->setResponse(
+            'HTTP/1.1 200 OK' . "\r\n" .
+            'Context-Type: text/html' . "\r\n\r\n" .
+            $body
+        );
+        $response = $this->gcm->send($this->message);
+        $result = $response->getResults();
+        $result = array_shift($result);
+        $this->assertEquals('1:2342', $result['message_id']);
+        $this->assertEquals(1, $response->getSuccessCount());
+        $this->assertEquals(0, $response->getCanonicalCount());
+        $this->assertEquals(0, $response->getFailureCount());
+    }
+
+    public function testSendResultSuccessfulWithRegistrationId()
+    {
+        $body = $this->_createJSONResponse(101, 1, 0, 1, array(array('message_id' => '1:2342', 'registration_id' => 'testfoo')));
+        $this->adapter->setResponse(
+            'HTTP/1.1 200 OK' . "\r\n" .
+            'Context-Type: text/html' . "\r\n\r\n" .
+            $body
+        );
+        $response = $this->gcm->send($this->message);
+        $result = $response->getResults();
+        $result = array_shift($result);
+        $this->assertEquals('1:2342', $result['message_id']);
+        $this->assertEquals('testfoo', $result['registration_id']);
+        $this->assertEquals(1, $response->getSuccessCount());
+        $this->assertEquals(1, $response->getCanonicalCount());
+        $this->assertEquals(0, $response->getFailureCount());
+    }
+}

+ 2 - 2
tests/Zend/Mobile/Push/Message/AllTests.php

@@ -27,7 +27,7 @@ if (!defined('PHPUnit_MAIN_METHOD')) {
 require_once 'Zend/Mobile/Push/Message/Mpns/AllTests.php';
 require_once 'Zend/Mobile/Push/Message/AbstractTest.php';
 require_once 'Zend/Mobile/Push/Message/ApnsTest.php';
-require_once 'Zend/Mobile/Push/Message/C2dmTest.php';
+require_once 'Zend/Mobile/Push/Message/GcmTest.php';
 
 /**
  * @category   Zend
@@ -52,7 +52,7 @@ class Zend_Mobile_Push_Message_AllTests
          
         $suite->addTestSuite('Zend_Mobile_Push_Message_AbstractTest');
         $suite->addTestSuite('Zend_Mobile_Push_Message_ApnsTest');
-        $suite->addTestSuite('Zend_Mobile_Push_Message_C2dmTest');
+        $suite->addTestSuite('Zend_Mobile_Push_Message_GcmTest');
 
         return $suite;
     }

+ 48 - 23
tests/Zend/Mobile/Push/Message/C2dmTest.php → tests/Zend/Mobile/Push/Message/GcmTest.php

@@ -20,7 +20,7 @@
  * @version    $Id $
  */
 
-require_once 'Zend/Mobile/Push/Message/C2dm.php';
+require_once 'Zend/Mobile/Push/Message/Gcm.php';
 
 /**
  * @category   Zend
@@ -30,16 +30,16 @@ require_once 'Zend/Mobile/Push/Message/C2dm.php';
  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  * @group      Zend_Mobile
  * @group      Zend_Mobile_Push
- * @group      Zend_Mobile_Push_C2dm
+ * @group      Zend_Mobile_Push_Gcm
  */
-class Zend_Mobile_Push_Message_C2dmTest extends PHPUnit_Framework_TestCase
+class Zend_Mobile_Push_Message_GcmTest extends PHPUnit_Framework_TestCase
 {
     /**
      * @expectedException Zend_Mobile_Push_Message_Exception
      */
     public function testAddDataThrowsExceptionOnNonStringKey()
     {
-        $msg = new Zend_Mobile_Push_Message_C2dm();
+        $msg = new Zend_Mobile_Push_Message_Gcm();
         $msg->addData(array(), 'value');
     }
 
@@ -48,7 +48,7 @@ class Zend_Mobile_Push_Message_C2dmTest extends PHPUnit_Framework_TestCase
      */
     public function testAddDataThrowsExceptionOnNonScalarValue()
     {
-        $msg = new Zend_Mobile_Push_Message_C2dm();
+        $msg = new Zend_Mobile_Push_Message_Gcm();
         $msg->addData('key', new stdClass);
     }
 
@@ -56,7 +56,7 @@ class Zend_Mobile_Push_Message_C2dmTest extends PHPUnit_Framework_TestCase
     {
         $data = array('key' => 'value');
         $data2 = array('key2' => 'value2');
-        $msg = new Zend_Mobile_Push_Message_C2dm();
+        $msg = new Zend_Mobile_Push_Message_Gcm();
 
         $msg->setData($data);
         $this->assertEquals($data, $msg->getData());
@@ -65,9 +65,26 @@ class Zend_Mobile_Push_Message_C2dmTest extends PHPUnit_Framework_TestCase
         $this->assertEquals($data2, $msg->getData());
     }
 
+    public function testTokens()
+    {
+        $msg = new Zend_Mobile_Push_Message_Gcm();
+        $msg->setToken('foo');
+        $this->assertEquals(array('foo'), $msg->getToken());
+
+        $msg->setToken(array('foo', 'bar'));
+        $this->assertEquals(array('foo', 'bar'), $msg->getToken());
+
+        $msg->setToken('bar');
+        $msg->addToken('foo');
+        $this->assertEquals(array('bar', 'foo'), $msg->getToken());
+
+        $msg->clearToken();
+        $this->assertEquals(array(), $msg->getToken());
+    }
+
     public function testDelayWhileIdle()
     {
-        $msg = new Zend_Mobile_Push_Message_C2dm();
+        $msg = new Zend_Mobile_Push_Message_Gcm();
         $msg->setDelayWhileIdle(true);
         $this->assertTrue($msg->getDelayWhileIdle());
         $msg->setDelayWhileIdle(false);
@@ -79,37 +96,45 @@ class Zend_Mobile_Push_Message_C2dmTest extends PHPUnit_Framework_TestCase
      */
     public function testDelayWhileIdleThrowsExceptionOnInvalidValue()
     {
-        $msg = new Zend_Mobile_Push_Message_C2dm();
+        $msg = new Zend_Mobile_Push_Message_Gcm();
         $msg->setDelayWhileIdle('true');
     }
 
-    public function testValidateWithoutTokenReturnsFalse()
+    public function testTtl()
     {
-        $msg = new Zend_Mobile_Push_Message_C2dm();
-        $msg->setId('collapseKey');
-        $this->assertFalse($msg->validate());
+        $msg = new Zend_Mobile_Push_Message_Gcm();
+        $msg->setTtl(10);
+        $this->assertEquals(10, $msg->getTtl());
     }
 
-    public function testValidateWithoutIdReturnsFalse()
+    /**
+     * @expectedException Zend_Mobile_Push_Message_Exception
+     */
+    public function testTtlThrowsExceptionOnInvalidValue()
     {
-        $msg = new Zend_Mobile_Push_Message_C2dm();
-        $msg->setToken('a-token!');
+        $msg = new Zend_Mobile_Push_Message_Gcm();
+        $msg->setTtl('foo');
+    }
+
+
+    public function testValidateWithoutTokenReturnsFalse()
+    {
+        $msg = new Zend_Mobile_Push_Message_Gcm();
         $this->assertFalse($msg->validate());
     }
 
-    public function testValidateWithIdAndTokenReturnsTrue()
+    public function testValidateToken()
     {
-        $msg = new Zend_Mobile_Push_Message_C2dm();
-        $msg->setId('collapseKey');
+        $msg = new Zend_Mobile_Push_Message_Gcm();
         $msg->setToken('a-token!');
         $this->assertTrue($msg->validate());
     }
 
-    public function testValidateWithIdAsIntAndTokenReturnsTrue()
+    public function testValidateWithTtlAndNoIdReturnsFalse()
     {
-        $msg = new Zend_Mobile_Push_Message_C2dm();
-        $msg->setId(time());
-        $msg->setToken('da-token');
-        $this->assertTrue($msg->validate());
+        $msg = new Zend_Mobile_Push_Message_Gcm();
+        $msg->setToken('foo');
+        $msg->setTtl(10);
+        $this->assertFalse($msg->validate());
     }
 }

+ 58 - 0
tests/Zend/Mobile/Push/Response/AllTests.php

@@ -0,0 +1,58 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mobile
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php $
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Mobile_Push_Response_AllTests::main');
+}
+
+require_once 'Zend/Mobile/Push/Response/GcmTest.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Mobile_Push_Response
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @group      Zend_Mobile
+ */
+class Zend_Mobile_Push_Response_AllTests
+{
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    public static function suite()
+    {
+        $suite = new PHPUnit_Framework_TestSuite('Zend Framework - Zend_Mobile_Push_Response');
+
+        $suite->addTest(Zend_Mobile_Push_Response_Mpns_AllTests::suite());
+         
+        $suite->addTestSuite('Zend_Mobile_Push_Response_GcmTest');
+
+        return $suite;
+    }
+}
+
+if (PHPUnit_MAIN_METHOD == 'Zend_Mobile_Push_Response_AllTests::main') {
+    Zend_Mobile_Push_Response_AllTests::main();
+}

+ 109 - 0
tests/Zend/Mobile/Push/Response/GcmTest.php

@@ -0,0 +1,109 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mobile
+ * @subpackage Push
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id $
+ */
+
+require_once 'Zend/Mobile/Push/Response/Gcm.php';
+require_once 'Zend/Mobile/Push/Message/Gcm.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Mobile
+ * @subpackage Push
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @group      Zend_Mobile
+ * @group      Zend_Mobile_Push
+ * @group      Zend_Mobile_Push_Gcm
+ */
+class Zend_Mobile_Push_Response_GcmTest extends PHPUnit_Framework_TestCase
+{
+    public function testConstructor()
+    {
+        $response = new Zend_Mobile_Push_Response_Gcm();
+        $this->assertNull($response->getResponse());
+        $this->assertNull($response->getMessage());
+
+        $message = new Zend_Mobile_Push_Message_Gcm();
+        $response = new Zend_Mobile_Push_Response_Gcm(null, $message);
+        $this->assertEquals($message, $response->getMessage());
+        $this->assertNull($response->getResponse());
+
+        $message = new Zend_Mobile_Push_Message_Gcm();
+        $responseArr = json_encode(array(
+            'results' => array(
+                array('message_id' => '1:1234'),
+            ),
+            'success' => 1,
+            'failure' => 0,
+            'canonical_ids' => 0,
+            'multicast_id' => 1,
+        ));
+        $response = new Zend_Mobile_Push_Response_Gcm($responseArr, $message);
+        $this->assertEquals(json_decode($responseArr, true), $response->getResponse());
+        $this->assertEquals($message, $response->getMessage());
+    }
+
+    /**
+     * @expectedException Zend_Mobile_Push_Exception_ServerUnavailable
+     */
+    public function testConstructorThrowsExceptionOnBadOrEmptyJsonString()
+    {
+        $response = new Zend_Mobile_Push_Response_Gcm('{bad');
+    }
+
+    public function testSetGetMessage()
+    {
+        $message = new Zend_Mobile_Push_Message_Gcm();
+        $response = new Zend_Mobile_Push_Response_Gcm();
+        $response->setMessage($message);
+        $this->assertEquals($message, $response->getMessage());
+    }
+
+    public function testResponse()
+    {
+        $responseArr = array(
+            'results' => array(
+                array('message_id' => '1:234'),
+            ),
+            'success' => 1,
+            'failure' => 0,
+            'canonical_ids' => 0,
+            'multicast_id' => '123',
+        );
+        $response = new Zend_Mobile_Push_Response_Gcm();
+        $response->setResponse($responseArr);
+        $this->assertEquals($responseArr, $response->getResponse());
+        $this->assertEquals(1, $response->getSuccessCount());
+        $this->assertEquals(0, $response->getFailureCount());
+        $this->assertEquals(0, $response->getCanonicalCount());
+        // test results non correlated
+        $expected = array(array('message_id' => '1:234'));
+        $this->assertEquals($expected, $response->getResults());
+        $expected = array(0 => '1:234');
+        $this->assertEquals($expected, $response->getResult(Zend_Mobile_Push_Response_Gcm::RESULT_MESSAGE_ID));
+
+        $message = new Zend_Mobile_Push_Message_Gcm();
+        $message->setToken(array('ABCDEF'));
+        $response->setMessage($message);
+        $expected = array('ABCDEF' => '1:234');
+        $this->assertEquals($expected, $response->getResult(Zend_Mobile_Push_Response_Gcm::RESULT_MESSAGE_ID));
+    }
+}