Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 1f30821333099ddc07fe7f90073f82ef0e0ce1e6 @willdurand committed Jan 18, 2013
@@ -0,0 +1 @@
+/vendor/
@@ -0,0 +1,12 @@
+language: php
+
+php:
+ - 5.3
+ - 5.4
+ - 5.5
+
+before_script:
+ - curl -s http://getcomposer.org/installer | php
+ - php composer.phar install --dev
+
+script: phpunit --coverage-text
@@ -0,0 +1,64 @@
+Negotiation
+===========
+
+Yet another missing PHP library... about Content Negotiation!
+**Negotiation** is a standalone library without any dependencies that allows you
+to implement [content
+negotiation](http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html) in your
+application, whatever framework you use.
+
+
+Installation
+------------
+
+The recommended way to install Negotiation is through composer:
+
+``` json
+{
+ "require": {
+ "willdurand/negotiation": "*"
+ }
+}
+```
+
+
+Usage
+-----
+
+``` php
+<?php
+
+$negotiator = new Negotiation\FormatNegotiator();
+$acceptHeader = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
+$priorities = array('html', 'json', '*/*');
+
+$format = $negotiator->getBest($acceptHeader, $priorities);
+// $format = html
+```
+
+
+Unit Tests
+----------
+
+Setup the project using Composer:
+
+ $ composer install --dev
+
+And, run the test suite:
+
+ $ phpunit
+
+
+Credits
+-------
+
+* Some parts of this library come from the
+[Symfony](http://github.com/symfony/symfony) framework.
+
+* William Durand <william.durand1@gmail.com>
+
+
+License
+-------
+
+Negotiation is released under the MIT License. See the bundled LICENSE file for details.
@@ -0,0 +1,17 @@
+{
+ "name": "willdurand/negotiation",
+ "description": "A Negotiation library",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "William DURAND",
+ "email": "william.durand1@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "autoload": {
+ "psr-0": { "Negotiation": "src/" }
+ }
+}
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit backupGlobals="false"
+ backupStaticAttributes="false"
+ colors="true"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ processIsolation="false"
+ stopOnFailure="false"
+ syntaxCheck="false"
+ bootstrap="tests/bootstrap.php"
+ >
+ <testsuites>
+ <testsuite name="Negotiation Test Suite">
+ <directory>./tests/</directory>
+ </testsuite>
+ </testsuites>
+ <filter>
+ <whitelist>
+ <directory>./src/Negotiation/</directory>
+ </whitelist>
+ </filter>
+</phpunit>
@@ -0,0 +1,111 @@
+<?php
+
+namespace Negotiation;
+
+/**
+ * @author William Durand <william.durand1@gmail.com>
+ */
+class FormatNegotiator extends Negotiator
+{
+ // https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/Request.php
+ private $formats = array(
+ 'html' => array('text/html', 'application/xhtml+xml'),
+ 'txt' => array('text/plain'),
+ 'js' => array('application/javascript', 'application/x-javascript', 'text/javascript'),
+ 'css' => array('text/css'),
+ 'json' => array('application/json', 'application/x-json'),
+ 'xml' => array('text/xml', 'application/xml', 'application/x-xml'),
+ 'rdf' => array('application/rdf+xml'),
+ 'atom' => array('application/atom+xml'),
+ 'rss' => array('application/rss+xml'),
+ );
+
+ /**
+ * Register a new format with its mime types.
+ *
+ * @param string $format
+ * @param array $mimeTypes
+ * @param boolean $override
+ */
+ public function registerFormat($format, array $mimeTypes, $override = false)
+ {
+ if (isset($this->formats[$format]) && false === $override) {
+ throw new \InvalidArgumentException(sprintf(
+ 'Format "%s" already registered, and override was set to "false".',
+ $format
+ ));
+ }
+
+ $this->formats[$format] = $mimeTypes;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getBest($acceptHeader, array $priorities = array())
+ {
+ $mimeTypes = $this->parseAcceptHeader($acceptHeader);
+ $catchAllEnabled = in_array('*/*', $priorities);
+
+ return $this->guessBestFormat($mimeTypes, $priorities, $catchAllEnabled);
+ }
+
+ /**
+ * Guess the best format based on a set of mime types.
+ *
+ * @param array $mimeTypes
+ * @param array $priorities
+ * @param boolean $catchAllEnabled
+ *
+ * @return string|null
+ */
+ public function guessBestFormat(array $mimeTypes, array $priorities = array(), $catchAllEnabled = false)
+ {
+ $max = reset($mimeTypes);
+ $keys = array_keys($mimeTypes, $max);
+
+ $formats = array();
+ foreach ($keys as $mimeType) {
+ unset($mimeTypes[$mimeType]);
+
+ if ($mimeType === '*/*') {
+ return reset($priorities);
+ }
+
+ if ($format = $this->getFormat($mimeType)) {
+ if (false !== $priority = array_search($format, $priorities)) {
+ $formats[$format] = $priority;
+ } elseif ($catchAllEnabled) {
+ $formats[$format] = count($priorities);
+ }
+ }
+ }
+
+ if (empty($formats) && !empty($mimeTypes)) {
+ return $this->guessBestFormat($mimeTypes, $priorities, $catchAllEnabled);
+ }
+
+ asort($formats);
+
+ return key($formats);
+ }
+
+ /**
+ * Returns the format for a given mime type, or null
+ * if not found.
+ *
+ * @param string $mimeType
+ *
+ * @return string|null
+ */
+ public function getFormat($mimeType)
+ {
+ foreach ($this->formats as $format => $mimeTypes) {
+ if (in_array($mimeType, (array) $mimeTypes)) {
+ return $format;
+ }
+ }
+
+ return null;
+ }
+}
@@ -0,0 +1,76 @@
+<?php
+
+namespace Negotiation;
+
+/**
+ * @author William Durand <william.durand1@gmail.com>
+ */
+class Negotiator implements NegotiatorInterface
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function getBest($acceptHeader, array $priorities = array())
+ {
+ $accepts = $this->parseAcceptHeader($acceptHeader);
+
+ if (0 === count($accepts)) {
+ return null;
+ }
+
+ if (0 !== count($priorities)) {
+ $priorities = array_map('strtolower', $priorities);
+
+ foreach ($accepts as $value => $quality) {
+ if (0 !== $quality && in_array($value, $priorities)) {
+ return $value;
+ }
+ }
+ }
+
+ return key($accepts);
+ }
+
+ /**
+ * @param string $acceptHeader
+ *
+ * @return array
+ */
+ public function parseAcceptHeader($acceptHeader)
+ {
+ $acceptHeader = preg_replace('/\s+/', '', $acceptHeader);
+ $acceptParts = preg_split('/\s*(?:,*("[^"]+"),*|,*(\'[^\']+\'),*|,+)\s*/',
+ $acceptHeader, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE
+ );
+
+ $accepts = array();
+ $index = 0;
+ foreach ($acceptParts as $accept) {
+ $quality = 1;
+
+ if (false !== strpos($accept, ';q=')) {
+ list($accept, $quality) = explode(';q=', $accept);
+ }
+
+ $accepts[$accept] = array(
+ 'quality' => $quality,
+ 'index' => $index
+ );
+
+ $index++;
+ }
+
+ uasort($accepts, function ($a, $b) {
+ $qA = $a['quality'];
+ $qB = $b['quality'];
+
+ if ($qA === $qB) {
+ return $a['index'] > $b['index'] ? 1 : -1;
+ }
+
+ return $qA > $qB ? -1 : 1;
+ });
+
+ return $accepts;
+ }
+}
@@ -0,0 +1,17 @@
+<?php
+
+namespace Negotiation;
+
+/**
+ * @author William Durand <william.durand1@gmail.com>
+ */
+interface NegotiatorInterface
+{
+ /**
+ * @param string $acceptHeader
+ * @param array $priorities
+ *
+ * @return string
+ */
+ public function getBest($acceptHeader, array $priorities = array());
+}
Oops, something went wrong.

0 comments on commit 1f30821

Please sign in to comment.