diff --git a/.travis.yml b/.travis.yml index 361f4ffb6a..4456cdd837 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,7 @@ before_install: - php dump_credentials.php script: + # run bigquery tests - cd bigquery/api - composer install - phpunit mainTest.php @@ -36,4 +37,9 @@ script: - cd datastore - composer install - phpunit test - - cd .. \ No newline at end of file + - cd .. + # run pubsub tests + - cd pubsub + - composer install + - phpunit test + - cd .. diff --git a/datastore/src/DatastoreHelper.php b/datastore/src/DatastoreHelper.php index e3de7beb95..4b92f9b651 100644 --- a/datastore/src/DatastoreHelper.php +++ b/datastore/src/DatastoreHelper.php @@ -28,7 +28,7 @@ class DatastoreHelper /** * Creates a query object for pulling the last $limit number of - * "PubSubMessage" items, equivalent to the following GQL: + * "DatastoreComment" items, equivalent to the following GQL: * * SELECT * from DatastoreComment ORDER BY created DESC LIMIT 20 * diff --git a/pubsub/README.md b/pubsub/README.md new file mode 100644 index 0000000000..ef9999ff87 --- /dev/null +++ b/pubsub/README.md @@ -0,0 +1,86 @@ +# Google PubSub PHP Sample Application + +## Description + +Note: The push endpoints don't work with the App Engine's local +devserver. The push notifications will go to an HTTP URL on the App +Engine server even when you run this sample locally. So we recommend +you deploy and run the app on App Engine. +TODO(tmatsuo): Better implementation for devserver. + +## Register your application + +- Go to + [Google Developers Console](https://console.developers.google.com/project) + and create a new project. This will automatically enable an App + Engine application with the same ID as the project. + +- Enable the "Google Cloud Pub/Sub" API under "APIs & auth > APIs." +- Enable the "Google Cloud Datastore" API under "APIs & auth > APIs." +- For local development also follow the instructions below. + - Go to "Credentials" and create a new Service Account. + - Select "Generate new JSON key", then download a new JSON file. + - Set the following environment variable: + - `GOOGLE_APPLICATION_CREDENTIALS`: the file path to the downloaded JSON file. + +## Prerequisites + +- Install [`composer`](https://getcomposer.org) +- Install the App Engine Python SDK. + We recommend you install + [Cloud SDK](https://developers.google.com/cloud/sdk/) rather than + just installing App Engine SDK. + +- Install Google API client library for PHP into 'lib' directory by running: + +``` +$ composer install +``` + +## Configuration + +Run the following commands to create your pubsub subscription topic: + +```sh +$ gcloud alpha pubsub topics create [your-topic-name] +1 topic(s) created successfully + - projects/[your-project-name]/topics/[your-topic-name] +``` + +> We use **`php-pubsub-example`** as the topic name, but you can change this +> by setting the `PUBSUB_TOPIC` environment variable (see `app.yaml`) + +Then you need to create your subscription to this topic by supplying +the endpoint to be notified when the topic is published to: + +``` +gcloud alpha pubsub subscriptions create [your-subscription-name] \ + --topic [your-topic-name] \ + --push-endpoint https://[your-project-name].appspot.com/receive_message \ + –-ack-deadline 30 +``` + +## Deploy the application to App Engine + +``` +$ gcloud preview app deploy app.yaml --set-default --project YOUR_PROJECT_NAME +``` + +Then access the following URL: + https://{YOUR_PROJECT_NAME}.appspot.com/ + +## Run the application locally + +``` +$ dev_appserver.py -A your-project-name . +``` + +## Contributing changes + +* See [CONTRIBUTING.md](../CONTRIBUTING.md) + +## Licensing + +* See [LICENSE](../LICENSE) + + diff --git a/pubsub/app.yaml b/pubsub/app.yaml new file mode 100644 index 0000000000..453cdd7d12 --- /dev/null +++ b/pubsub/app.yaml @@ -0,0 +1,12 @@ +runtime: php55 +api_version: 1 +threadsafe: true + +handlers: +- url: /js + static_dir: web/js +- url: /.* + script: web/index.php + +env_variables: + GOOGLE_PROJECT_NAME: "YOUR_PROJECT_NAME" \ No newline at end of file diff --git a/pubsub/composer.json b/pubsub/composer.json new file mode 100644 index 0000000000..b72ff39683 --- /dev/null +++ b/pubsub/composer.json @@ -0,0 +1,19 @@ +{ + "autoload": { + "psr-4": { + "Google\\Cloud\\Samples\\Pubsub\\": "src" + } + }, + "require": { + "php": ">=5.4", + "silex/silex": "~1.3", + "twig/twig": "~1.8|~2.0", + "symfony/twig-bridge": "~2.7|3.0.*", + "google/apiclient": "~2.0@rc" + }, + "require-dev": { + "symfony/dom-crawler": "~2.0", + "symfony/css-selector": "~2.0", + "symfony/browser-kit": "~2.7" + } +} diff --git a/pubsub/composer.lock b/pubsub/composer.lock new file mode 100644 index 0000000000..56e7c84ee4 --- /dev/null +++ b/pubsub/composer.lock @@ -0,0 +1,1301 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "64f927cfd0fadb8190e20bb3cdca8c5f", + "content-hash": "da5fdd6614a3830a70452e1a469c698d", + "packages": [ + { + "name": "firebase/php-jwt", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "fa8a06e96526eb7c0eeaa47e4f39be59d21f16e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/fa8a06e96526eb7c0eeaa47e4f39be59d21f16e1", + "reference": "fa8a06e96526eb7c0eeaa47e4f39be59d21f16e1", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "time": "2015-07-22 18:31:08" + }, + { + "name": "google/apiclient", + "version": "v2.0.0-RC2", + "source": { + "type": "git", + "url": "https://github.com/google/google-api-php-client.git", + "reference": "3905a254d513236810b2451b1805507782bde313" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/google/google-api-php-client/zipball/3905a254d513236810b2451b1805507782bde313", + "reference": "3905a254d513236810b2451b1805507782bde313", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "~2.0|~3.0", + "google/auth": "~0.4", + "guzzlehttp/guzzle": "5.2.*", + "monolog/monolog": "^1.17", + "php": ">=5.4", + "phpseclib/phpseclib": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~4", + "squizlabs/php_codesniffer": "~2.3", + "symfony/css-selector": "~2.0", + "symfony/dom-crawler": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Google_": "src/" + }, + "classmap": [ + "src/Google/Service/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "time": "2015-11-10 04:11:33" + }, + { + "name": "google/auth", + "version": "v0.4", + "source": { + "type": "git", + "url": "https://github.com/google/google-auth-library-php.git", + "reference": "b2d0e7bdcbe8ccdd0f83a7527ef23bcc202e331a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/google/google-auth-library-php/zipball/b2d0e7bdcbe8ccdd0f83a7527ef23bcc202e331a", + "reference": "b2d0e7bdcbe8ccdd0f83a7527ef23bcc202e331a", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "~2.0|~3.0", + "guzzlehttp/guzzle": "5.2.*", + "php": ">=5.4" + }, + "require-dev": { + "phplint/phplint": "0.0.1", + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ], + "psr-4": { + "Google\\Auth\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google Auth Library for PHP", + "homepage": "http://github.com/google/google-auth-library-php", + "keywords": [ + "Authentication", + "google", + "oauth2" + ], + "time": "2015-11-03 23:16:35" + }, + { + "name": "guzzlehttp/guzzle", + "version": "5.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "475b29ccd411f2fa8a408e64576418728c032cfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/475b29ccd411f2fa8a408e64576418728c032cfa", + "reference": "475b29ccd411f2fa8a408e64576418728c032cfa", + "shasum": "" + }, + "require": { + "guzzlehttp/ringphp": "~1.0", + "php": ">=5.4.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0", + "psr/log": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2015-01-28 01:03:29" + }, + { + "name": "guzzlehttp/ringphp", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/RingPHP.git", + "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", + "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", + "shasum": "" + }, + "require": { + "guzzlehttp/streams": "~3.0", + "php": ">=5.4.0", + "react/promise": "~2.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "ext-curl": "Guzzle will use specific adapters if cURL is present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Ring\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.", + "time": "2015-05-20 03:37:09" + }, + { + "name": "guzzlehttp/streams", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/streams.git", + "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", + "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Provides a simple abstraction over streams of data", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "stream" + ], + "time": "2014-10-12 19:18:40" + }, + { + "name": "monolog/monolog", + "version": "1.17.2", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "bee7f0dc9c3e0b69a6039697533dca1e845c8c24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bee7f0dc9c3e0b69a6039697533dca1e845c8c24", + "reference": "bee7f0dc9c3e0b69a6039697533dca1e845c8c24", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "jakub-onderka/php-parallel-lint": "0.9", + "php-console/php-console": "^3.1.3", + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "2.3.0", + "raven/raven": "^0.13", + "ruflin/elastica": ">=0.90 <3.0", + "swiftmailer/swiftmailer": "~5.3", + "videlalvaro/php-amqplib": "~2.4" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "raven/raven": "Allow sending log messages to a Sentry server", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.16.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be/" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2015-10-14 12:51:02" + }, + { + "name": "phpseclib/phpseclib", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "a74aa9efbe61430fcb60157c8e025a48ec8ff604" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/a74aa9efbe61430fcb60157c8e025a48ec8ff604", + "reference": "a74aa9efbe61430fcb60157c8e025a48ec8ff604", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phing/phing": "~2.7", + "phpunit/phpunit": "~4.0", + "sami/sami": "~2.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "suggest": { + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.", + "pear-pear/PHP_Compat": "Install PHP_Compat to get phpseclib working on PHP < 5.0.0." + }, + "type": "library", + "autoload": { + "psr-4": { + "phpseclib\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "phpseclib/" + ], + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net/", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "time": "2015-08-04 04:48:03" + }, + { + "name": "pimple/pimple", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Pimple.git", + "reference": "2019c145fe393923f3441b23f29bbdfaa5c58c4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/2019c145fe393923f3441b23f29bbdfaa5c58c4d", + "reference": "2019c145fe393923f3441b23f29bbdfaa5c58c4d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Pimple": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple is a simple Dependency Injection Container for PHP 5.3", + "homepage": "http://pimple.sensiolabs.org/", + "keywords": [ + "container", + "dependency injection" + ], + "time": "2013-11-22 08:30:29" + }, + { + "name": "psr/log", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2012-12-21 11:40:51" + }, + { + "name": "react/promise", + "version": "v2.2.1", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/3b6fca09c7d56321057fa8867c8dbe1abf648627", + "reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "React\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "time": "2015-07-03 13:48:55" + }, + { + "name": "silex/silex", + "version": "v1.3.4", + "source": { + "type": "git", + "url": "https://github.com/silexphp/Silex.git", + "reference": "d6de62716fcda76084f3015165125f30b1563517" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/silexphp/Silex/zipball/d6de62716fcda76084f3015165125f30b1563517", + "reference": "d6de62716fcda76084f3015165125f30b1563517", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "pimple/pimple": "~1.0", + "symfony/event-dispatcher": "~2.3|3.0.*", + "symfony/http-foundation": "~2.3|3.0.*", + "symfony/http-kernel": "~2.3|3.0.*", + "symfony/routing": "~2.3|3.0.*" + }, + "require-dev": { + "doctrine/dbal": "~2.2", + "monolog/monolog": "^1.4.1", + "swiftmailer/swiftmailer": "~5", + "symfony/browser-kit": "~2.3|3.0.*", + "symfony/config": "~2.3|3.0.*", + "symfony/css-selector": "~2.3|3.0.*", + "symfony/debug": "~2.3|3.0.*", + "symfony/dom-crawler": "~2.3|3.0.*", + "symfony/finder": "~2.3|3.0.*", + "symfony/form": "~2.3|3.0.*", + "symfony/locale": "~2.3|3.0.*", + "symfony/monolog-bridge": "~2.3|3.0.*", + "symfony/options-resolver": "~2.3|3.0.*", + "symfony/phpunit-bridge": "~2.7", + "symfony/process": "~2.3|3.0.*", + "symfony/security": "~2.3|3.0.*", + "symfony/serializer": "~2.3|3.0.*", + "symfony/translation": "~2.3|3.0.*", + "symfony/twig-bridge": "~2.3|3.0.*", + "symfony/validator": "~2.3|3.0.*", + "twig/twig": "~1.8|~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Silex\\": "src/Silex" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "The PHP micro-framework based on the Symfony Components", + "homepage": "http://silex.sensiolabs.org/", + "keywords": [ + "microframework" + ], + "time": "2015-09-15 06:53:42" + }, + { + "name": "symfony/debug", + "version": "v2.7.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "fb9e6887db716939f41af0ba8ef38a1582eb501b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/fb9e6887db716939f41af0ba8ef38a1582eb501b", + "reference": "fb9e6887db716939f41af0ba8ef38a1582eb501b", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/class-loader": "~2.2", + "symfony/http-kernel": "~2.3.24|~2.5.9|~2.6,>=2.6.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Debug Component", + "homepage": "https://symfony.com/", + "time": "2015-10-11 09:39:48" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.7.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "87a5db5ea887763fa3a31a5471b512ff1596d9b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/87a5db5ea887763fa3a31a5471b512ff1596d9b8", + "reference": "87a5db5ea887763fa3a31a5471b512ff1596d9b8", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.0,>=2.0.5", + "symfony/dependency-injection": "~2.6", + "symfony/expression-language": "~2.6", + "symfony/stopwatch": "~2.3" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com/", + "time": "2015-10-11 09:39:48" + }, + { + "name": "symfony/http-foundation", + "version": "v2.7.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "7598eea151ae3d4134df1f9957364b17809eea75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7598eea151ae3d4134df1f9957364b17809eea75", + "reference": "7598eea151ae3d4134df1f9957364b17809eea75", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/expression-language": "~2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony HttpFoundation Component", + "homepage": "https://symfony.com/", + "time": "2015-10-23 14:47:27" + }, + { + "name": "symfony/http-kernel", + "version": "v2.7.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "4260f2273a446a6715063dc9ca89fd0c475c2f77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/4260f2273a446a6715063dc9ca89fd0c475c2f77", + "reference": "4260f2273a446a6715063dc9ca89fd0c475c2f77", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "psr/log": "~1.0", + "symfony/debug": "~2.6,>=2.6.2", + "symfony/event-dispatcher": "~2.6,>=2.6.7", + "symfony/http-foundation": "~2.5,>=2.5.4" + }, + "conflict": { + "symfony/config": "<2.7" + }, + "require-dev": { + "symfony/browser-kit": "~2.3", + "symfony/class-loader": "~2.1", + "symfony/config": "~2.7", + "symfony/console": "~2.3", + "symfony/css-selector": "~2.0,>=2.0.5", + "symfony/dependency-injection": "~2.2", + "symfony/dom-crawler": "~2.0,>=2.0.5", + "symfony/expression-language": "~2.4", + "symfony/finder": "~2.0,>=2.0.5", + "symfony/process": "~2.0,>=2.0.5", + "symfony/routing": "~2.2", + "symfony/stopwatch": "~2.3", + "symfony/templating": "~2.2", + "symfony/translation": "~2.0,>=2.0.5", + "symfony/var-dumper": "~2.6" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/class-loader": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "", + "symfony/finder": "", + "symfony/var-dumper": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony HttpKernel Component", + "homepage": "https://symfony.com/", + "time": "2015-10-27 19:07:21" + }, + { + "name": "symfony/routing", + "version": "v2.7.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "f353e1f588679c3ec987624e6c617646bd01ba38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/f353e1f588679c3ec987624e6c617646bd01ba38", + "reference": "f353e1f588679c3ec987624e6c617646bd01ba38", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "conflict": { + "symfony/config": "<2.7" + }, + "require-dev": { + "doctrine/annotations": "~1.0", + "doctrine/common": "~2.2", + "psr/log": "~1.0", + "symfony/config": "~2.7", + "symfony/expression-language": "~2.4", + "symfony/http-foundation": "~2.3", + "symfony/yaml": "~2.0,>=2.0.5" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/expression-language": "For using expression matching", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Routing Component", + "homepage": "https://symfony.com/", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "time": "2015-10-27 15:38:06" + }, + { + "name": "symfony/twig-bridge", + "version": "v2.7.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/twig-bridge.git", + "reference": "3dd44937b1e08af8c8f6b14850f4b9c4d1039c6f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/3dd44937b1e08af8c8f6b14850f4b9c4d1039c6f", + "reference": "3dd44937b1e08af8c8f6b14850f4b9c4d1039c6f", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "twig/twig": "~1.20|~2.0" + }, + "require-dev": { + "symfony/asset": "~2.7", + "symfony/console": "~2.7", + "symfony/expression-language": "~2.4", + "symfony/finder": "~2.3", + "symfony/form": "~2.7,>=2.7.6", + "symfony/http-kernel": "~2.3", + "symfony/intl": "~2.3", + "symfony/routing": "~2.2", + "symfony/security": "~2.6", + "symfony/security-acl": "~2.6", + "symfony/stopwatch": "~2.2", + "symfony/templating": "~2.1", + "symfony/translation": "~2.7", + "symfony/var-dumper": "~2.6", + "symfony/yaml": "~2.0,>=2.0.5" + }, + "suggest": { + "symfony/asset": "For using the AssetExtension", + "symfony/expression-language": "For using the ExpressionExtension", + "symfony/finder": "", + "symfony/form": "For using the FormExtension", + "symfony/http-kernel": "For using the HttpKernelExtension", + "symfony/routing": "For using the RoutingExtension", + "symfony/security": "For using the SecurityExtension", + "symfony/stopwatch": "For using the StopwatchExtension", + "symfony/templating": "For using the TwigEngine", + "symfony/translation": "For using the TranslationExtension", + "symfony/var-dumper": "For using the DumpExtension", + "symfony/yaml": "For using the YamlExtension" + }, + "type": "symfony-bridge", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Twig\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Twig Bridge", + "homepage": "https://symfony.com/", + "time": "2015-10-11 09:39:48" + }, + { + "name": "twig/twig", + "version": "v1.23.1", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/d9b6333ae8dd2c8e3fd256e127548def0bc614c6", + "reference": "d9b6333ae8dd2c8e3fd256e127548def0bc614c6", + "shasum": "" + }, + "require": { + "php": ">=5.2.7" + }, + "require-dev": { + "symfony/debug": "~2.7", + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.23-dev" + } + }, + "autoload": { + "psr-0": { + "Twig_": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org/", + "role": "Lead Developer" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + }, + { + "name": "Twig Team", + "homepage": "http://twig.sensiolabs.org/contributors", + "role": "Contributors" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "http://twig.sensiolabs.org/", + "keywords": [ + "templating" + ], + "time": "2015-11-05 12:49:06" + } + ], + "packages-dev": [ + { + "name": "symfony/browser-kit", + "version": "v2.7.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "07d664a052572ccc28eb2ab7dbbe82155b1ad367" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/07d664a052572ccc28eb2ab7dbbe82155b1ad367", + "reference": "07d664a052572ccc28eb2ab7dbbe82155b1ad367", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/dom-crawler": "~2.0,>=2.0.5" + }, + "require-dev": { + "symfony/css-selector": "~2.0,>=2.0.5", + "symfony/process": "~2.3.34|~2.7,>=2.7.6" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony BrowserKit Component", + "homepage": "https://symfony.com/", + "time": "2015-10-23 14:47:27" + }, + { + "name": "symfony/css-selector", + "version": "v2.7.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "e1b865b26be4a56d22a8dee398375044a80c865b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/e1b865b26be4a56d22a8dee398375044a80c865b", + "reference": "e1b865b26be4a56d22a8dee398375044a80c865b", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com/", + "time": "2015-10-11 09:39:48" + }, + { + "name": "symfony/dom-crawler", + "version": "v2.7.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "5fef7d8b80d8f9992df99d8ee283f420484c9612" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/5fef7d8b80d8f9992df99d8ee283f420484c9612", + "reference": "5fef7d8b80d8f9992df99d8ee283f420484c9612", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/css-selector": "~2.3" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DomCrawler Component", + "homepage": "https://symfony.com/", + "time": "2015-10-11 09:39:48" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "google/apiclient": 5 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.4" + }, + "platform-dev": [] +} diff --git a/pubsub/php.ini b/pubsub/php.ini new file mode 100644 index 0000000000..4cae2279fa --- /dev/null +++ b/pubsub/php.ini @@ -0,0 +1,2 @@ +google_app_engine.enable_functions = "php_sapi_name, php_uname" +extension = "curl.so" \ No newline at end of file diff --git a/pubsub/src/DatastoreHelper.php b/pubsub/src/DatastoreHelper.php new file mode 100644 index 0000000000..54e069a29e --- /dev/null +++ b/pubsub/src/DatastoreHelper.php @@ -0,0 +1,170 @@ +client = $client; + $this->datasetId = $datasetId; + } + + /** + * Creates a query object for pulling the last $limit number of + * "PubSubMessage" items, equivalent to the following GQL: + * + * SELECT * from PubSubMessage ORDER BY created DESC LIMIT 20 + * + * @see https://cloud.google.com/datastore/docs/concepts/gql + */ + public function createQuery($limit = 20) + { + $request = new \Google_Service_Datastore_RunQueryRequest(); + $query = new \Google_Service_Datastore_Query(); + + $order = new \Google_Service_Datastore_PropertyOrder(); + $order->setDirection('descending'); + $property = new \Google_Service_Datastore_PropertyReference(); + $property->setName('created'); + $order->setProperty($property); + $query->setOrder([$order]); + + $kind = new \Google_Service_Datastore_KindExpression(); + $kind->setName('PubSubMessage'); + $query->setKinds([$kind]); + + $query->setLimit($limit); + + $request->setQuery($query); + + return $request; + } + + /** + * Creates the request to store a PubSubMessage item in datastore + */ + public function createMessageRequest(\Google_Service_Datastore_Key $id, $message) + { + $entity = $this->createEntity($id, $message); + $mutation = new \Google_Service_Datastore_Mutation(); + $mutation->setUpsert([$entity]); + $req = new \Google_Service_Datastore_CommitRequest(); + $req->setMode('NON_TRANSACTIONAL'); + $req->setMutation($mutation); + + return $req; + } + + /** + * Creates the basic entity for PubSubMessage, with properties "created" + * and "message" + */ + public function createEntity(\Google_Service_Datastore_Key $key, $message) + { + $entity = new \Google_Service_Datastore_Entity(); + $entity->setKey($key); + $messageProp = new \Google_Service_Datastore_Property(); + $messageProp->setStringValue($message); + $createdProp = new \Google_Service_Datastore_Property(); + $createdProp->setDateTimeValue(date('c')); + $properties = [ + 'message' => $messageProp, + 'created' => $createdProp, + ]; + + $entity->setProperties($properties); + + return $entity; + } + + /** + * Fetches a unique key from Datastore for a PubSub message + */ + public function createUniqueKeyRequest() + { + // retrieve a unique ID from datastore + $path = new \Google_Service_Datastore_KeyPathElement(); + $path->setKind('PubSubMessage'); + $key = new \Google_Service_Datastore_Key(); + $key->setPath([$path]); + $idRequest = new \Google_Service_Datastore_AllocateIdsRequest(); + $idRequest->setKeys([$key]); + + return $idRequest; + } + + /** + * Queries the Datastore API for all messages and returns as an array + * + * @see createQuery + * @return array + */ + public function fetchMessages() + { + $datastore = new \Google_Service_Datastore($this->client); + + $query = $this->createQuery(); + + $response = $datastore->datasets->runQuery($this->datasetId, $query); + + $messages = []; + foreach ($response->getBatch()->getEntityResults() as $entityResult) { + $properties = $entityResult->getEntity()->getProperties(); + $messages[] = $properties['message']->getStringValue(); + } + + return $messages; + } + + /** + * Stores a single message in Datastore using the Datastore API + * + * @param string $message + * @return bool + */ + public function storeMessage($message) + { + $datastore = new \Google_Service_Datastore($this->client); + + $idRequest = $this->createUniqueKeyRequest(); + $uniqueId = $datastore->datasets->allocateIds($this->datasetId, $idRequest); + $key = $uniqueId->getKeys()[0]; + + // build the API request to send using the key and message + $request = $this->createMessageRequest($key, $message); + + return $datastore->datasets->commit($this->datasetId, $request); + } +} \ No newline at end of file diff --git a/pubsub/src/app.php b/pubsub/src/app.php new file mode 100644 index 0000000000..e3ceec7e12 --- /dev/null +++ b/pubsub/src/app.php @@ -0,0 +1,109 @@ +register(new TwigServiceProvider()); +$app['twig.path'] = [ __DIR__.'/../templates' ]; +$app['project_id'] = getenv('GOOGLE_PROJECT_NAME'); +$app['topic'] = getenv('TOPIC_NAME') ?: 'php-pubsub-example'; + +// Authenticate your API Client +$client = new Google_Client(); +$client->useApplicationDefaultCredentials(); +$client->addScope(Google_Service_Pubsub::PUBSUB); +$client->addScope(Google_Service_Datastore::DATASTORE); +$client->addScope(Google_Service_Datastore::USERINFO_EMAIL); + +$app['google_client'] = $client; + +$app->get('/', function () use ($app) { + return $app['twig']->render('pubsub.html.twig', [ + 'project_id' => $app['project_id'], + ]); +}); + +$app->get('/fetch_messages', function () use ($app) { + /** @var Google_Client $client */ + $client = $app['google_client']; + $projectId = $app['project_id']; + + // Retrieve all messages from datastore + // For a more complete demo of datastore, + // @see https://github.com/GoogleCloudPlatform/php-docs-samples/tree/master/datastore + $datastore = new DatastoreHelper($client, $projectId); + $messages = $datastore->fetchMessages(); + + return new JsonResponse($messages); +}); + +$app->post('/receive_message', function() use ($app) { + /** @var Google_Client $client */ + $client = $app['google_client']; + $projectId = $app['project_id']; + + // pull the message from the post body + $json = $app['request']->getContent(); + $request = json_decode($json, true); + if (!isset($request['message']['data']) || !$message = base64_decode($request['message']['data'])) { + return new Response('', 400); + } + + // Store the received message in datastore + // For a more complete demo of datastore, + // @see https://github.com/GoogleCloudPlatform/php-docs-samples/tree/master/datastore + $datastore = new DatastoreHelper($client, $projectId); + $datastore->storeMessage($message); + + return new Response(); +}); + +$app->post('/send_message', function() use ($app) { + // send the pubsub message + if ($messageText = $app['request']->get('message')) { + /** @var Google_Client $client */ + $client = $app['google_client']; + $projectName = sprintf('projects/%s', $app['project_id']); + $topicName = sprintf('%s/topics/%s', $projectName, $app['topic']); + + $pubsub = new Google_Service_Pubsub($client); + + // create pubsub message object + $message = new Google_Service_Pubsub_PubsubMessage(); + $message->setData(base64_encode($messageText)); + // create pubsub request + $request = new Google_Service_Pubsub_PublishRequest(); + $request->setMessages([$message]); + + $pubsub->projects_topics->publish($topicName, $request); + + return new Response('', 204); + } + + return new Response('', 400); +}); + +return $app; diff --git a/pubsub/templates/pubsub.html.twig b/pubsub/templates/pubsub.html.twig new file mode 100644 index 0000000000..adace5842d --- /dev/null +++ b/pubsub/templates/pubsub.html.twig @@ -0,0 +1,33 @@ + + + + + Hello Cloud Pub/Sub + + + +

Hello Cloud Pub/Sub!

+ + Project: {{ project_id }}
+ +
+ +
+ + + + per seconds. + {{ "{{ PubsubController.errorNotice }}" }} + +

Messages:

+ + + + + diff --git a/pubsub/test/DatastoreHelperTest.php b/pubsub/test/DatastoreHelperTest.php new file mode 100644 index 0000000000..ee82ef3499 --- /dev/null +++ b/pubsub/test/DatastoreHelperTest.php @@ -0,0 +1,49 @@ +getMock('Google_Client'); + $datastore = new DatastoreHelper($client, 'test-dataset-id'); + + $request = $datastore->createQuery(14); + + $this->assertInstanceOf('Google_Service_Datastore_RunQueryRequest', $request); + $this->assertEquals(14, $request->getQuery()->getLimit()); + } + + public function testCreateEntity() + { + $client = $this->getMock('Google_Client'); + $datastore = new DatastoreHelper($client, 'test-dataset-id'); + + $key = $this->getMock('Google_Service_Datastore_Key'); + $entity = $datastore->createEntity($key, 'my test message'); + + $this->assertInstanceOf('Google_Service_Datastore_Entity', $entity); + + $properties = $entity->getProperties(); + $this->assertArrayHasKey('message', $properties); + + $properties = $entity->getProperties(); + $this->assertEquals('my test message', $properties['message']->getStringValue()); + } + + public function testCreateUniqueKeyRequest() + { + $client = $this->getMock('Google_Client'); + $datastore = new DatastoreHelper($client, 'test-dataset-id'); + + $key = $datastore->createUniqueKeyRequest(); + + $this->assertInstanceOf('Google_Service_Datastore_AllocateIdsRequest', $key); + } +} \ No newline at end of file diff --git a/pubsub/test/pubsubTest.php b/pubsub/test/pubsubTest.php new file mode 100644 index 0000000000..8f7c53a55b --- /dev/null +++ b/pubsub/test/pubsubTest.php @@ -0,0 +1,130 @@ +markTestSkipped('credentials not found'); + } + + // prevent HTML error exceptions + unset($app['exception_handler']); + + return $app; + } + + public function testInitialPage() + { + // create the application + $client = $this->createClient(); + + // make the request + $crawler = $client->request('GET', '/'); + + // test the response + $this->assertTrue($client->getResponse()->isOk()); + } + + public function testFetchMessages() + { + // set up mock objects + $apiResponse = new \Google_Service_Datastore_RunQueryResponse(); + $apiResponse->setBatch(new \Google_Service_Datastore_QueryResultBatch()); + $apiClient = $this->getMock('Google_Client'); + $apiClient + ->expects($this->once()) + ->method('execute') + ->will($this->returnValue($apiResponse)); + $apiClient + ->expects($this->once()) + ->method('getLogger') + ->will($this->returnValue($this->getMock('Psr\Log\LoggerInterface'))); + $apiClient + ->expects($this->once()) + ->method('getHttpClient') + ->will($this->returnValue(new HttpClient())); + + // create the application + $app = $this->createApplication(); + $app['google_client'] = $apiClient; + $client = new Client($app); + + // make the request + $crawler = $client->request('GET', '/fetch_messages'); + + // test the response + $response = $client->getResponse(); + $this->assertTrue($response->isOk()); + $this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response); + $this->assertEquals('[]', $response->getContent()); + } + + public function testSendMessage() + { + // set up mock objects + $apiClient = $this->getMock('Google_Client'); + $apiClient + ->expects($this->once()) + ->method('execute') + ->will($this->returnValue(true)); + $apiClient + ->expects($this->once()) + ->method('getLogger') + ->will($this->returnValue($this->getMock('Psr\Log\LoggerInterface'))); + $apiClient + ->expects($this->once()) + ->method('getHttpClient') + ->will($this->returnValue(new HttpClient())); + + // create the application + $app = $this->createApplication(); + $app['google_client'] = $apiClient; + $client = new Client($app); + + // make the request + $crawler = $client->request('POST', '/send_message', ['message' => 'foo']); + + // test the response + $response = $client->getResponse(); + $this->assertEquals(204, $response->getStatusCode()); + } +} \ No newline at end of file diff --git a/pubsub/web/index.php b/pubsub/web/index.php new file mode 100644 index 0000000000..ac0d1c3a56 --- /dev/null +++ b/pubsub/web/index.php @@ -0,0 +1,30 @@ +run(); diff --git a/pubsub/web/js/pubsub.js b/pubsub/web/js/pubsub.js new file mode 100644 index 0000000000..273440301c --- /dev/null +++ b/pubsub/web/js/pubsub.js @@ -0,0 +1,88 @@ + +'use strict'; + +var pubsub = pubsub || angular.module('pubsub', []); + +/** + * PubsubController. + * + * @NgInject + */ +pubsub.PubsubController = function($http, $log, $timeout) { + this.promise = null; + this.logger = $log; + this.http = $http; + this.timeout = $timeout; + this.interval = 1; + this.isAutoUpdating = true; + this.failCount = 0; + this.fetchMessages(); +}; + +pubsub.PubsubController.MAX_FAILURE_COUNT = 3; + +pubsub.PubsubController.TIMEOUT_MULTIPLIER = 1000; + +/** + * Toggles the auto update flag. + */ +pubsub.PubsubController.prototype.toggleAutoUpdate = function() { + this.isAutoUpdating = !this.isAutoUpdating; + if (this.isAutoUpdating) { + this.logger.info('Start fetching.'); + this.fetchMessages(); + } else if (this.promise !== null) { + this.logger.info('Cancel the promise.'); + this.timeout.cancel(this.promise); + this.promise = null; + } +}; + +/** + * Sends a message + * + * @param {string} message + */ +pubsub.PubsubController.prototype.sendMessage = function(message) { + var self = this; + self.http({ + method: 'POST', + url: '/send_message', + data: 'message=' + encodeURIComponent(message), + headers: {'Content-Type': 'application/x-www-form-urlencoded'} + }).success(function(data, status) { + self.message = null; + }).error(function(data, status) { + self.logger.error('Failed to send the message. Status: ' + status + '.'); + }); +}; + +/** + * Continuously fetches messages from the server. + */ +pubsub.PubsubController.prototype.fetchMessages = function() { + var self = this; + self.http.get('/fetch_messages') + .success(function(data, status) { + self.messages = data; + self.failCount = 0; + }) + .error(function(data, status) { + self.logger.error('Failed to receive the messages. Status: ' + + status + '.'); + self.failCount += 1; + }); + if (self.failCount < pubsub.PubsubController.MAX_FAILURE_COUNT) { + if (self.isAutoUpdating) { + self.promise = self.timeout( + function() { self.fetchMessages(); }, + self.interval * pubsub.PubsubController.TIMEOUT_MULTIPLIER); + } + } else { + self.errorNotice = 'Maximum failure count reached, ' + + 'so stopped fetching messages.'; + self.logger.error(self.errorNotice); + self.isAutoUpdating = false; + self.failCount = 0; + } +};