Skip to content

Commit

Permalink
Merge pull request #5 from jcroll/development
Browse files Browse the repository at this point in the history
[RFC] HWI Oauth Bundle Support
  • Loading branch information
jcroll authored Aug 30, 2016
2 parents bf2c57b + a1443c2 commit 1c8a1e3
Show file tree
Hide file tree
Showing 8 changed files with 3,548 additions and 48 deletions.
17 changes: 16 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm

matrix:
include:
- php: 5.3
env: COMPOSER_FLAGS="--prefer-lowest"

before_script: composer install --dev
before_script:
- composer self-update
- composer update --prefer-dist --no-interaction $COMPOSER_FLAGS

script:
- ./vendor/bin/phpunit
97 changes: 85 additions & 12 deletions DependencyInjection/JcrollFoursquareApiExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;

Expand All @@ -12,26 +13,98 @@
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*/
class JcrollFoursquareApiExtension extends Extension
class JcrollFoursquareApiExtension extends Extension implements PrependExtensionInterface
{
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$config = $this->processConfiguration($configuration, $configs);

$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader = $this->getLoader($container);
$loader->load('services.xml');

$container->setParameter(
'jcroll_foursquare_api.client_id',
$config['client_id']
);
$container->setParameter(
'jcroll_foursquare_api.client_secret',
$config['client_secret']
);
$container->setParameter('jcroll_foursquare_api.client_id', $config['client_id']);
$container->setParameter('jcroll_foursquare_api.client_secret', $config['client_secret']);
}

/**
* {@inheritdoc}
*/
public function prepend(ContainerBuilder $container)
{
$bundles = $container->getParameter('kernel.bundles');

if (!isset($bundles['HWIOAuthBundle'])) {
return;
}

$config = $this->getExtensionConfig('jcroll_foursquare_api', $container, array('client_id', 'client_secret'));

if (null === $config) {
$this->prependCredentials($container);
}

$loader = $this->getLoader($container);
$loader->load('oauth.xml');
}

/**
* @param ContainerBuilder $container
*/
private function prependCredentials(ContainerBuilder $container)
{
if (!$config = $this->getExtensionConfig('hwi_oauth', $container, array('resource_owners'))) {
return;
}

$required = array('type', 'client_id', 'client_secret');

foreach ($config['resource_owners'] as $resourceOwner) {
// If not all required config keys are present
if (count(array_intersect_key($resourceOwner, array_flip($required))) !== 3) {
continue;
}

if ($resourceOwner['type'] !== 'foursquare') {
continue;
}

$container->prependExtensionConfig($this->getAlias(), array(
'client_id' => $resourceOwner['client_id'],
'client_secret' => $resourceOwner['client_secret'],
));
}
}

/**
* @param ContainerBuilder $container
*
* @return Loader\XmlFileLoader
*/
private function getLoader(ContainerBuilder $container)
{
return new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
}

/**
* @param string $extension
* @param ContainerBuilder $container
* @param array $required
*
* @return array|null
*/
private function getExtensionConfig($extension, ContainerBuilder $container, array $required)
{
$configs = $container->getExtensionConfig($extension);
$config = reset($configs);

if (count(array_intersect_key($config, array_flip($required))) !== count($required)) {
return null;
}

return $config;
}
}
45 changes: 45 additions & 0 deletions EventListener/OauthListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace Jcroll\FoursquareApiBundle\EventListener;

use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken;
use Jcroll\FoursquareApiClient\Client\FoursquareClient;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class OauthListener
{
/** @var TokenStorageInterface */
private $tokenStorage;

/** @var FoursquareClient */
private $client;

/**
* @param TokenStorageInterface $tokenStorage
* @param FoursquareClient $client
*/
public function __construct(TokenStorageInterface $tokenStorage, FoursquareClient $client)
{
$this->tokenStorage = $tokenStorage;
$this->client = $client;
}

/**
* @param GetResponseEvent $event
*/
public function onKernelRequest(GetResponseEvent $event)
{
$token = $this->tokenStorage->getToken();

if (!$token instanceof OAuthToken) {
return;
}

if ('foursquare' !== $token->getResourceOwnerName()) {
return;
}

$this->client->addToken($token->getAccessToken());
}
}
70 changes: 43 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

[![Build Status](https://travis-ci.org/jcroll/foursquare-api-bundle.png)](https://travis-ci.org/jcroll/foursquare-api-bundle)

This bundle integrates the [JcrollFoursquareApiClient](https://github.com/jcroll/foursquare-api-client) into the Symfony2
This bundle integrates the [JcrollFoursquareApiClient](https://github.com/jcroll/foursquare-api-client) into the Symfony
framework.

## Why?

There is no library built to interact with the [foursquare api](https://developer.foursquare.com/) using the fantastic
[Guzzle HTTP Client library](https://github.com/guzzle/guzzle). Guzzle is awesome and supplies a lot of great things
for building web service clients.
This bundle will allow you to easily configure the [JcrollFoursquareApiClient](https://github.com/jcroll/foursquare-api-client)
and additionally easily allow you to integrate with the [HWIOAuthBundle](https://github.com/hwi/HWIOAuthBundle)
(if you are using it) for signed requests to the foursquare api (see the
[JcrollFoursquareApiBundleSandbox](https://github.com/jcroll/foursquare-api-bundle-sandbox) for examples).

## Installation

Expand All @@ -18,7 +19,7 @@ Add JcrollFoursquareApiBundle in your composer.json:
```js
{
"require": {
"jcroll/foursquare-api-bundle": "1.0.*"
"jcroll/foursquare-api-bundle": "~1"
}
}
```
Expand Down Expand Up @@ -47,38 +48,53 @@ Add the JcrollFoursquareApiBundle to your AppKernel.php

## Basic configuration

Add your application id and secret parameters:

```yaml
# app/config/config.yml

jcroll_foursquare_api:
client_id: <your_foursquare_client_id>
client_secret: <your_foursquare_client_secret>
```
1. If you're not using [HWIOAuthBundle](https://github.com/hwi/HWIOAuthBundle) add your application id and secret
parameters:

```yaml
# app/config/config.yml

jcroll_foursquare_api:
client_id: <your_foursquare_client_id>
client_secret: <your_foursquare_client_secret>
```
2. If you are using [HWIOAuthBundle](https://github.com/hwi/HWIOAuthBundle) configure a `foursquare` resource owner
and the client's credentials will automatically be configured (that's right you do not need to define this bundle in
`config.yml`).

```yaml
# app/config/config.yml
hwi_oauth:
resource_owners:
any_name:
type: foursquare
client_id: <your_foursquare_client_id> # will automatically inject in the client
client_secret: <your_foursquare_client_secret> # will automatically inject in the client
```

## Usage

```php
$client = $this->container->get('jcroll_foursquare_client');
$client->addToken($oauthToken); // optional for user specific requests
$command = $client->getCommand('venues/search', array(
'near' => 'Chicago, IL',
$command = $client->getCommand('venues/search', [
'near' => 'Chicago, IL',
'query' => 'sushi'
));
$results = $command->execute();
]);
$results = (array) $client->execute($command); // returns an array of results
```

You can find a list of the client's available commands in the bundle's
[client.json](https://github.com/jcroll/foursquare-api-client/blob/master/lib/Jcroll/FoursquareApiClient/Resources/config/client.json)
[client.json](https://github.com/jcroll/foursquare-api-client/blob/master/src/Resources/config/client.json)
but basically they should be the same as the [api endpoints listed in the docs](https://developer.foursquare.com/docs/).

## Oauth2 Integration

Authorization for user specific requests at foursquare via the Oauth 2 protocol is beyond the scope of this bundle.
Here are two libraries you might use to do that:
## HWIOAuthBundle Integration

* [HWIOAuthBundle](https://github.com/hwi/HWIOAuthBundle)
* [FOSOAuthServerBundle](https://github.com/FriendsOfSymfony/FOSOAuthServerBundle)
If you are using [HWIOAuthBundle](https://github.com/hwi/HWIOAuthBundle) this bundle will automatically look for
a `resource_owner` of type `foursquare` in that bundle's configuration and inject the `client_id` and `client_secret`
into the `jcroll_foursquare_client` service (no need to configure this bundle).

After you receive your access token you can then pass it into the client as shown above.
Additionally a listener will be configured and if the authenticated user possesses an oauth token belonging to foursquare
the token will be automatically injected into the `jcroll_foursquare_client` service for signed requests (no need to call
`addToken`).
16 changes: 16 additions & 0 deletions Resources/config/oauth.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>

<service id="jcroll_foursquare_api.oauth_listener" class="Jcroll\FoursquareApiBundle\EventListener\OauthListener">
<argument type="service" id="security.token_storage" />
<argument type="service" id="jcroll_foursquare_api.foursquare_client" />
<tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" />
</service>

</services>
</container>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use Jcroll\FoursquareApiBundle\DependencyInjection\JcrollFoursquareApiExtension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;

class JcrollFoursquareApiExtensionTest extends \PHPUnit_Framework_TestCase
{
Expand All @@ -15,17 +14,17 @@ class JcrollFoursquareApiExtensionTest extends \PHPUnit_Framework_TestCase
public function testLoadEmptyConfiguration()
{
$config = array(
'client_id' => '',
'client_id' => '',
'client_secret' => ''
);

$container = $this->createCompiledContainerForConfig($config);
$this->createCompiledContainerForConfig($config);
}

public function testLoadConfiguration()
{
$config = array(
'client_id' => 'aClientId',
'client_id' => 'aClientId',
'client_secret' => 'aClientSecret'
);

Expand Down Expand Up @@ -54,6 +53,7 @@ private function createContainer($debug = false)
'kernel.cache_dir' => __DIR__,
'kernel.charset' => 'UTF-8',
'kernel.debug' => $debug,
'kernel.bundles' => array('JcrollFoursquareApiBundle')
)));

return $container;
Expand Down
10 changes: 6 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@
],
"require": {
"jcroll/foursquare-api-client": ">=1",
"symfony/framework-bundle": ">=2.6"
"symfony/framework-bundle": ">=2.7"
},
"require-dev": {
"phpunit/phpunit": "~4.8|^5"
},
"autoload": {
"psr-0": {
"Jcroll\\FoursquareApiBundle": ""
"psr-4": {
"Jcroll\\FoursquareApiBundle\\": ""
}
},
"target-dir": "Jcroll/FoursquareApiBundle",
"minimum-stability": "dev",
"extra": {
"branch-alias": {
Expand Down
Loading

0 comments on commit 1c8a1e3

Please sign in to comment.