From b772951ebedf105daf118bde8d53800743cab757 Mon Sep 17 00:00:00 2001 From: Lyndon Brown Date: Sat, 26 Jan 2013 03:58:36 +0000 Subject: [PATCH 1/8] Add composer.lock to .gitignore --- .gitignore | 3 +- composer.lock | 235 -------------------------------------------------- 2 files changed, 2 insertions(+), 236 deletions(-) delete mode 100644 composer.lock diff --git a/.gitignore b/.gitignore index 22d0d82..de4a392 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -vendor +/vendor +/composer.lock diff --git a/composer.lock b/composer.lock deleted file mode 100644 index e232ffc..0000000 --- a/composer.lock +++ /dev/null @@ -1,235 +0,0 @@ -{ - "hash": "fbaad4ca06268918d11410b6f0e70525", - "packages": [ - { - "package": "doctrine/common", - "version": "2.3.x-dev", - "source-reference": "2ec4bc6db13db6a0976a16b71058083c55cbcdbd", - "commit-date": "1343847076" - }, - { - "package": "friendsofsymfony/rest", - "version": "dev-master", - "alias-pretty-version": "0.7.x-dev", - "alias-version": "0.7.9999999.9999999-dev" - }, - { - "package": "friendsofsymfony/rest", - "version": "dev-master", - "source-reference": "5ea703f5a3f5c7110cadeccb91b212c0eb7ea2d0", - "commit-date": "1339701893" - }, - { - "package": "friendsofsymfony/rest-bundle", - "version": "dev-master", - "alias-pretty-version": "0.8.x-dev", - "alias-version": "0.8.9999999.9999999-dev" - }, - { - "package": "friendsofsymfony/rest-bundle", - "version": "dev-master", - "source-reference": "d3f15d6c913d25fe5b29185e6e6be510afd09c73", - "commit-date": "1345237156" - }, - { - "package": "jms/metadata", - "version": "dev-master", - "alias-pretty-version": "1.2.x-dev", - "alias-version": "1.2.9999999.9999999-dev" - }, - { - "package": "jms/metadata", - "version": "dev-master", - "source-reference": "7c58d49ff13de62464837c3c7d91aff1deb2c442", - "commit-date": "1345552810" - }, - { - "package": "jms/serializer-bundle", - "version": "dev-master", - "alias-pretty-version": "0.9.x-dev", - "alias-version": "0.9.9999999.9999999-dev" - }, - { - "package": "jms/serializer-bundle", - "version": "dev-master", - "source-reference": "1f308a587742246e87e580290f3bae23073d1d70", - "commit-date": "1343641450" - }, - { - "package": "pimple/pimple", - "version": "dev-master", - "alias-pretty-version": "1.0.x-dev", - "alias-version": "1.0.9999999.9999999-dev" - }, - { - "package": "pimple/pimple", - "version": "dev-master", - "source-reference": "db836b8cfadc0f39dacafa2bf311a1ab603600bb", - "commit-date": "1343051648" - }, - { - "package": "sensio/framework-extra-bundle", - "version": "dev-master", - "alias-pretty-version": "2.1.x-dev", - "alias-version": "2.1.9999999.9999999-dev" - }, - { - "package": "sensio/framework-extra-bundle", - "version": "dev-master", - "source-reference": "ade2d53b20a9fc3428f04c863b3fd4fca0b62181", - "commit-date": "1344072374" - }, - { - "package": "silex/silex", - "version": "dev-master", - "alias-pretty-version": "1.0.x-dev", - "alias-version": "1.0.9999999.9999999-dev" - }, - { - "package": "silex/silex", - "version": "dev-master", - "source-reference": "6d7cf048c704c0c58276b01eccfacab4dd11d013", - "commit-date": "1344453846" - }, - { - "package": "symfony/config", - "version": "dev-master", - "alias-pretty-version": "2.1.x-dev", - "alias-version": "2.1.9999999.9999999-dev" - }, - { - "package": "symfony/config", - "version": "dev-master", - "source-reference": "f68ad44f3ee1603ce96387bacba0ecba488c2a33", - "commit-date": "1344599303" - }, - { - "package": "symfony/dependency-injection", - "version": "dev-master", - "alias-pretty-version": "2.1.x-dev", - "alias-version": "2.1.9999999.9999999-dev" - }, - { - "package": "symfony/dependency-injection", - "version": "dev-master", - "source-reference": "98fa735a7ef5dc07c43bfe6faa4367a983b6ba6f", - "commit-date": "1344599303" - }, - { - "package": "symfony/event-dispatcher", - "version": "dev-master", - "alias-pretty-version": "2.1.x-dev", - "alias-version": "2.1.9999999.9999999-dev" - }, - { - "package": "symfony/event-dispatcher", - "version": "dev-master", - "source-reference": "76c76f62702b09e0f182ae618be0f1d79e2a711f", - "commit-date": "1345066712" - }, - { - "package": "symfony/filesystem", - "version": "dev-master", - "alias-pretty-version": "2.1.x-dev", - "alias-version": "2.1.9999999.9999999-dev" - }, - { - "package": "symfony/filesystem", - "version": "dev-master", - "source-reference": "72acf65c2390c9066e1174d269a4e146ffad9296", - "commit-date": "1344875591" - }, - { - "package": "symfony/framework-bundle", - "version": "dev-master", - "alias-pretty-version": "2.1.x-dev", - "alias-version": "2.1.9999999.9999999-dev" - }, - { - "package": "symfony/framework-bundle", - "version": "dev-master", - "source-reference": "4f0d296b4414cb5322e7ee45af117e5234bc75d0", - "commit-date": "1345278333" - }, - { - "package": "symfony/http-foundation", - "version": "dev-master", - "alias-pretty-version": "2.1.x-dev", - "alias-version": "2.1.9999999.9999999-dev" - }, - { - "package": "symfony/http-foundation", - "version": "dev-master", - "source-reference": "8d5e7f909fa519853e71bcfc57a1da8c637ebcbb", - "commit-date": "1345191498" - }, - { - "package": "symfony/http-kernel", - "version": "dev-master", - "alias-pretty-version": "2.1.x-dev", - "alias-version": "2.1.9999999.9999999-dev" - }, - { - "package": "symfony/http-kernel", - "version": "dev-master", - "source-reference": "0d0ee371ab0425f3399dba9e25d7ad98ca5c0d62", - "commit-date": "1344074675" - }, - { - "package": "symfony/routing", - "version": "dev-master", - "alias-pretty-version": "2.1.x-dev", - "alias-version": "2.1.9999999.9999999-dev" - }, - { - "package": "symfony/routing", - "version": "dev-master", - "source-reference": "v2.1.0-RC1", - "commit-date": "1343744077" - }, - { - "package": "symfony/serializer", - "version": "dev-master", - "alias-pretty-version": "2.1.x-dev", - "alias-version": "2.1.9999999.9999999-dev" - }, - { - "package": "symfony/serializer", - "version": "dev-master", - "source-reference": "v2.1.0-RC1", - "commit-date": "1343307511" - }, - { - "package": "symfony/templating", - "version": "dev-master", - "alias-pretty-version": "2.1.x-dev", - "alias-version": "2.1.9999999.9999999-dev" - }, - { - "package": "symfony/templating", - "version": "dev-master", - "source-reference": "v2.1.0-RC1", - "commit-date": "1343982509" - }, - { - "package": "symfony/translation", - "version": "dev-master", - "alias-pretty-version": "2.1.x-dev", - "alias-version": "2.1.9999999.9999999-dev" - }, - { - "package": "symfony/translation", - "version": "dev-master", - "source-reference": "d7a6083e76a3af3f247bff523bc47b41e7208a87", - "commit-date": "1344955085" - } - ], - "packages-dev": null, - "aliases": [ - - ], - "minimum-stability": "dev", - "stability-flags": [ - - ] -} From 00eccbcacdc091af79038911fe72e2a50d05e995 Mon Sep 17 00:00:00 2001 From: Lyndon Brown Date: Sat, 26 Jan 2013 04:02:35 +0000 Subject: [PATCH 2/8] Cleanup: Remove old autoloader code --- README.md | 5 +---- src/Flintstones/Rest/ServiceProvider.php | 8 -------- tests/Flintstones/Rest/Tests/ServiceProviderTest.php | 5 +---- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index d502f5f..4708bdc 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,7 @@ You get accept header support and request body decoding. ## Registering - $app->register(new Flintstones\Rest\ServiceProvider(), array( - 'rest.fos.class_path' => __DIR__.'/vendor', - 'rest.serializer.class_path' => __DIR__.'/vendor', - )); + $app->register(new Flintstones\Rest\ServiceProvider()); ## Running the tests diff --git a/src/Flintstones/Rest/ServiceProvider.php b/src/Flintstones/Rest/ServiceProvider.php index 8468619..e3fea2b 100644 --- a/src/Flintstones/Rest/ServiceProvider.php +++ b/src/Flintstones/Rest/ServiceProvider.php @@ -59,14 +59,6 @@ public function register(Application $app) 'xml' => 'rest.decoder.xml', ); - if (isset($app['rest.fos.class_path'])) { - $app['autoloader']->registerNamespace('FOS\RestBundle', $app['rest.fos.class_path']); - } - - if (isset($app['rest.serializer.class_path'])) { - $app['autoloader']->registerNamespace('Symfony\Component\Serializer', $app['rest.serializer.class_path']); - } - $listener = new BodyListener(new PimpleDecoderProvider($app, $app['rest.decoders'])); $app['dispatcher']->addListener(HttpKernelEvents::REQUEST, array($listener, 'onKernelRequest')); diff --git a/tests/Flintstones/Rest/Tests/ServiceProviderTest.php b/tests/Flintstones/Rest/Tests/ServiceProviderTest.php index b087cc4..8452f72 100644 --- a/tests/Flintstones/Rest/Tests/ServiceProviderTest.php +++ b/tests/Flintstones/Rest/Tests/ServiceProviderTest.php @@ -36,10 +36,7 @@ public function testRegister() { $app = new Application(); - $app->register(new RestServiceProvider(), array( - 'rest.fos.class_path' => __DIR__.'/../../../../vendor', - 'rest.serializer.class_path' => __DIR__.'/../../../../vendor', - )); + $app->register(new RestServiceProvider()); $this->assertInstanceOf('Symfony\Component\Serializer\Serializer', $app['rest.serializer']); From 160c7189e1d3c3d419b8e3ede1d364b279297fd1 Mon Sep 17 00:00:00 2001 From: Lyndon Brown Date: Sat, 26 Jan 2013 04:03:13 +0000 Subject: [PATCH 3/8] Cleanup: Remove unnecessary and unused parameters for FormatNegotiator() --- src/Flintstones/Rest/ServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Flintstones/Rest/ServiceProvider.php b/src/Flintstones/Rest/ServiceProvider.php index e3fea2b..33397c0 100644 --- a/src/Flintstones/Rest/ServiceProvider.php +++ b/src/Flintstones/Rest/ServiceProvider.php @@ -43,7 +43,7 @@ public function register(Application $app) } $app['rest.format_negotiator'] = function ($app) { - return new FormatNegotiator($app['request'], $app['rest.priorities']); + return new FormatNegotiator(); }; $app['rest.decoder.json'] = function ($app) { From 4b699f58ca256b89dde4522806b6e00bf56c7021 Mon Sep 17 00:00:00 2001 From: Lyndon Brown Date: Sat, 26 Jan 2013 04:04:37 +0000 Subject: [PATCH 4/8] Cleanup: Fix indentation and remove unnecessary comments around boot() method, inline with (most) service providers included in Silex --- src/Flintstones/Rest/ServiceProvider.php | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/Flintstones/Rest/ServiceProvider.php b/src/Flintstones/Rest/ServiceProvider.php index 33397c0..dabc605 100644 --- a/src/Flintstones/Rest/ServiceProvider.php +++ b/src/Flintstones/Rest/ServiceProvider.php @@ -65,15 +65,7 @@ public function register(Application $app) $listener = new FormatListener($app['rest.format_negotiator'], 'html', $app['rest.priorities']); $app['dispatcher']->addListener(HttpKernelEvents::CONTROLLER, array($listener, 'onKernelController'), 10); } - - /** - * Bootstraps the application. - * - * This method is called after all services are registers - * and should be used for "dynamic" configuration (whenever - * a service must be requested). - */ - public function boot(Application $app) { - // TODO: Implement boot() method. - } + + public function boot(Application $app) { + } } From caa9e40dcce58dcb49cf9cde554517414485b5d0 Mon Sep 17 00:00:00 2001 From: Lyndon Brown Date: Sat, 26 Jan 2013 04:21:07 +0000 Subject: [PATCH 5/8] Allow over-riding fallback format --- src/Flintstones/Rest/ServiceProvider.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Flintstones/Rest/ServiceProvider.php b/src/Flintstones/Rest/ServiceProvider.php index dabc605..85a1aee 100644 --- a/src/Flintstones/Rest/ServiceProvider.php +++ b/src/Flintstones/Rest/ServiceProvider.php @@ -42,6 +42,10 @@ public function register(Application $app) $app['rest.priorities'] = array('json', 'xml'); } + if (!isset($app['rest.fallback'])) { + $app['rest.fallback'] = 'html'; + } + $app['rest.format_negotiator'] = function ($app) { return new FormatNegotiator(); }; @@ -62,7 +66,7 @@ public function register(Application $app) $listener = new BodyListener(new PimpleDecoderProvider($app, $app['rest.decoders'])); $app['dispatcher']->addListener(HttpKernelEvents::REQUEST, array($listener, 'onKernelRequest')); - $listener = new FormatListener($app['rest.format_negotiator'], 'html', $app['rest.priorities']); + $listener = new FormatListener($app['rest.format_negotiator'], $app['rest.fallback'], $app['rest.priorities']); $app['dispatcher']->addListener(HttpKernelEvents::CONTROLLER, array($listener, 'onKernelController'), 10); } From a4d20cd0e547c6efcdaac27dc3eaa775fc08ffba Mon Sep 17 00:00:00 2001 From: Lyndon Brown Date: Sat, 26 Jan 2013 05:18:41 +0000 Subject: [PATCH 6/8] Add a cleaner (parameter) method for overridding things, along with documentation --- README.md | 59 ++++++++++++++++++++++++ src/Flintstones/Rest/ServiceProvider.php | 11 +++++ 2 files changed, 70 insertions(+) diff --git a/README.md b/README.md index 4708bdc..b888b5a 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,65 @@ You get accept header support and request body decoding. $app->register(new Flintstones\Rest\ServiceProvider()); +## Overriding parameters + +The following can be overridden: + +* `'rest.priorities'` + This is an array of formats your code is capable of + sending back a response as. A negotiation takes place + to determine which is most suitable based on the + request's Accept header. +* `'rest.fallback'` + This is the format to fall back on if no suitable + format could be negotiated. This can be set to NULL + if you would like a 406 HTTP status error to be + returned instead. +* `'rest.decoders'` + This is an array that refers to decoder services + which are used to decode request body content. + Default decoders are included for JSON and XML, + but you can override this if necessary. + +Any of these you wish to override must be overridden +prior to the service completing its setup, i.e. before +its `register()` method has executed. Therefore they must +either be set on `$app` prior to registering the service, +or they must be given in an array to it's constructor +(*not* the second optional parameter of `$app->register()` +unlike most Silex service providers). + +Example #1: + + $app->register(new Flintstones\Rest\ServiceProvider(array( + 'rest.priorities' => array('html', 'json', 'xml'), + 'rest.fallback' => null, + ))); + +Example #2: + + $app['rest.priorities'] = array('html', 'json', 'xml'); + $app['rest.fallback'] = null; + + $app->register(new Flintstones\Rest\ServiceProvider()); + +Example #3: + + $app['rest.decoders.custom'] = function ($app) { + //code... + }; + + $app->register(new Flintstones\Rest\ServiceProvider(array( + 'rest.decoders' => array( + 'json' => 'rest.decoders.json', + 'xml' => 'rest.decoders.xml', + 'custom' => 'rest.decoders.custom', + ), + ))); + +Note that if you wish to replace `$app['rest.decoder.json']` +and/or `$app['rest.decoder.xml']`, do so after registering. + ## Running the tests $ curl -s https://getcomposer.org/installer | php diff --git a/src/Flintstones/Rest/ServiceProvider.php b/src/Flintstones/Rest/ServiceProvider.php index 85a1aee..ef978df 100644 --- a/src/Flintstones/Rest/ServiceProvider.php +++ b/src/Flintstones/Rest/ServiceProvider.php @@ -27,8 +27,19 @@ class ServiceProvider implements ServiceProviderInterface { + private $parameters = array(); + + public function __construct(array $parameters = array()) + { + $this->parameters = $parameters; + } + public function register(Application $app) { + foreach ($this->parameters as $key => $parameter) { + $app[$key] = $parameter; + } + $app['rest.serializer'] = $app->share(function () { $encoders = array ( 'json' => new JsonEncoder(), From d243370c2362ab99896ea3fe09dd66407b84f267 Mon Sep 17 00:00:00 2001 From: Lyndon Brown Date: Sat, 26 Jan 2013 06:48:52 +0000 Subject: [PATCH 7/8] Add tests: Service provider response format tests --- .../Rest/Tests/ServiceProviderFormatsTest.php | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 tests/Flintstones/Rest/Tests/ServiceProviderFormatsTest.php diff --git a/tests/Flintstones/Rest/Tests/ServiceProviderFormatsTest.php b/tests/Flintstones/Rest/Tests/ServiceProviderFormatsTest.php new file mode 100644 index 0000000..375dc8c --- /dev/null +++ b/tests/Flintstones/Rest/Tests/ServiceProviderFormatsTest.php @@ -0,0 +1,186 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flintstones\Rest\Tests; + +use Flintstones\Rest\ServiceProvider as RestServiceProvider; + +use Silex\Application; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\HttpException; +use Symfony\Component\HttpKernel\HttpKernelInterface; + +/** + * Test format listener determins correct response + * + * @author Igor Wiedler + */ +class ServiceProviderResponseFormatTest extends \PHPUnit_Framework_TestCase +{ + private $app; + + public function setUp() + { + $this->app = new Application(); + } + + /** + * Test with a set of priorities and a fallback + * + * @dataProvider providerFormatSelection + */ + public function testFormatSelection($accept, array $priorities, $expected) + { + $app = $this->app; + + $app->register(new RestServiceProvider(array( + 'rest.priorities' => $priorities, + ))); + + $app->get('/foo', function () use ($app) { + return $app['request']->getRequestFormat(); + }); + + $request = Request::create('/foo'); + $request->headers->set('Accept', $accept); + $response = $app->handle($request, HttpKernelInterface::MASTER_REQUEST, false); + + $this->assertEquals($expected, $response->getContent()); + } + + public function providerFormatSelection() + { + $priorities = array('json', 'xml'); + + return array( + array('application/json', $priorities, 'json'), + array('application/json;q=0.1', $priorities, 'json'), + array('text/xml', $priorities, 'xml'), + array('text/html', $priorities, 'html'), + array('application/json;q=0.9,text/xml', $priorities, 'xml'), + array('application/json;q=0.9,text/xml;q=0.8', $priorities, 'json'), + array('x/x', $priorities, 'html'), + array('x/x;q=1,application/json;q=0.1', $priorities, 'json'), + array('*/*', $priorities, 'json'), + ); + } + + /** + * Test with no priorities but with a fallback + * + * This fallback should always be picked here (following the logic of + * the FOS\RestBundle\EventListener\FormatListener() method used here). + * + * @dataProvider providerFallbackOnly + */ + public function testFallbackOnly($fallback) + { + $app = $this->app; + + $app->register(new RestServiceProvider(array( + 'rest.priorities' => array(), + 'rest.fallback' => $fallback, + ))); + + $app->get('/foo', function () use ($app) { + return $app['request']->getRequestFormat(); + }); + + $request = Request::create('/foo'); + $request->headers->set('Accept', 'application/json'); + $response = $app->handle($request, HttpKernelInterface::MASTER_REQUEST, false); + + $this->assertEquals($fallback, $response->getContent()); + } + + public function providerFallbackOnly() + { + return array( + array('html'), + array('json'), + array('xml'), + ); + } + + /** + * Test with priorities but no fallback + * + * This should result in an exception / 406 error if no format can be negotiated. + */ + public function testNoFallback() + { + $app = $this->app; + + $app->register(new RestServiceProvider(array( + 'rest.priorities' => array('html', 'json'), + 'rest.fallback' => null, + ))); + + $app->get('/foo', function () use ($app) { + return $app['request']->getRequestFormat(); + }); + + $request = Request::create('/foo'); + $request->headers->set('Accept', 'text/xml'); + $response = $app->handle($request, HttpKernelInterface::MASTER_REQUEST, true); + + $this->assertEquals(406, $response->getStatusCode()); + + try { + $request = Request::create('/foo'); + $request->headers->set('Accept', 'text/xml'); + $response = $app->handle($request, HttpKernelInterface::MASTER_REQUEST, false); + + $this->fail('An expected HttpException exception has not been raised.'); + } + catch (HttpException $e) { + return; + } + } + + /** + * Test with no priorities and no fallback + * + * This should never be done, but it is expected to always result in an + * exception / 406 error, so this tests that expectation. + */ + public function testNoPrioritiesNoFallback() + { + $app = $this->app; + + $app->register(new RestServiceProvider(array( + 'rest.priorities' => array(), + 'rest.fallback' => null, + ))); + + $app->get('/foo', function () use ($app) { + return $app['request']->getRequestFormat(); + }); + + $request = Request::create('/foo'); + $request->headers->set('Accept', 'application/json'); + $response = $app->handle($request, HttpKernelInterface::MASTER_REQUEST, true); + + $this->assertEquals(406, $response->getStatusCode()); + + try { + $request = Request::create('/foo'); + $request->headers->set('Accept', 'application/json'); + $response = $app->handle($request, HttpKernelInterface::MASTER_REQUEST, false); + + $this->fail('An expected HttpException exception has not been raised.'); + } + catch (HttpException $e) { + return; + } + } +} From d300fabcaf923aa0f5591ad59efa55e90c7367f1 Mon Sep 17 00:00:00 2001 From: Lyndon Brown Date: Sun, 27 Jan 2013 23:04:32 +0000 Subject: [PATCH 8/8] Fix wrong author --- tests/Flintstones/Rest/Tests/ServiceProviderFormatsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Flintstones/Rest/Tests/ServiceProviderFormatsTest.php b/tests/Flintstones/Rest/Tests/ServiceProviderFormatsTest.php index 375dc8c..13cbc43 100644 --- a/tests/Flintstones/Rest/Tests/ServiceProviderFormatsTest.php +++ b/tests/Flintstones/Rest/Tests/ServiceProviderFormatsTest.php @@ -22,7 +22,7 @@ /** * Test format listener determins correct response * - * @author Igor Wiedler + * @author Lyndon Brown */ class ServiceProviderResponseFormatTest extends \PHPUnit_Framework_TestCase {