Skip to content

Commit

Permalink
Backport fix for #38 and #39 from 1.3
Browse files Browse the repository at this point in the history
  • Loading branch information
iby authored and willdurand committed Oct 2, 2014
1 parent fa1283e commit 1749792
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 33 deletions.
32 changes: 32 additions & 0 deletions src/Negotiation/LanguageNegotiator.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,36 @@ protected function parseHeader($header)

return $this->sortAcceptHeaders($acceptHeaders, $catchAll);
}

/**
* {@inheritDoc}
*/
protected function match(array $acceptHeaders, array $priorities = array())
{
$wildcardAccept = null;

$prioritiesSet = array();
$prioritiesSet[] = $priorities;
$prioritiesSet[] = array_map(function ($priority) {
return strtok($priority, '-');
}, $priorities);

foreach ($acceptHeaders as $accept) {
foreach ($prioritiesSet as $availablePriorities) {
$sanitizedPriorities = $this->sanitize($availablePriorities);

if (false !== $found = array_search(strtolower($accept->getValue()), $sanitizedPriorities)) {
return $priorities[$found];
}

if ('*' === $accept->getValue()) {
$wildcardAccept = $accept;
}
}
}

if (null !== $wildcardAccept) {
return reset($priorities);
}
}
}
53 changes: 33 additions & 20 deletions src/Negotiation/Negotiator.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,13 @@ public function getBest($header, array $priorities = array())
return null;
}

if (0 !== count($priorities)) {
$priorities = $this->sanitize($priorities);

$wildcardAccept = null;
foreach ($acceptHeaders as $accept) {
if (in_array(strtolower($accept->getValue()), $priorities)) {
return $accept;
}

if ('*' === $accept->getValue()) {
$wildcardAccept = $accept;
}
}

if (null !== $wildcardAccept) {
$value = reset($priorities);

return new AcceptHeader($value, $wildcardAccept->getQuality(), $this->parseParameters($value));
}
if (0 === count($priorities)) {
return reset($acceptHeaders);
}

return reset($acceptHeaders);
$value = $this->match($acceptHeaders, $priorities);

return empty($value) ? null : new AcceptHeader($value, 1.0, $this->parseParameters($value));
}

/**
Expand Down Expand Up @@ -168,4 +153,32 @@ protected function parseParameters($value)

return $parameters;
}

/**
* @param AcceptHeader[] $acceptHeaders Sorted by quality
* @param array $priorities Configured priorities
*
* @return string|null Header string matched
*/
protected function match(array $acceptHeaders, array $priorities = array())
{
$wildcardAccept = null;
$sanitizedPriorities = $this->sanitize($priorities);

foreach ($acceptHeaders as $accept) {
if (false !== $found = array_search(strtolower($accept->getValue()), $sanitizedPriorities)) {
return $priorities[$found];
}

if ('*' === $accept->getValue()) {
$wildcardAccept = $accept;
}
}

if (null !== $wildcardAccept) {
return reset($priorities);
}

return null;
}
}
4 changes: 4 additions & 0 deletions tests/Negotiation/Tests/AcceptHeaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

class AcceptHeaderTest extends TestCase
{

/**
* @var AcceptHeader
*/
private $acceptHeader;

protected function setUp()
Expand Down
23 changes: 18 additions & 5 deletions tests/Negotiation/Tests/FormatNegotiatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
*/
class FormatNegotiatorTest extends TestCase
{

/**
* @var FormatNegotiator
*/
private $negotiator;

protected function setUp()
Expand All @@ -28,7 +32,7 @@ public function testGetBest($acceptHeader, $priorities, $expected)
} else {
$this->assertNotNull($acceptHeader);
if (is_array($expected)) {
$this->assertEquals($expected['value'], $acceptHeader->getValue());
$this->assertEquals($expected['value'], $acceptHeader->getValue());
$this->assertEquals($expected['quality'], $acceptHeader->getQuality());

if (isset($expected['parameters'])) {
Expand Down Expand Up @@ -331,7 +335,7 @@ public function testRegisterFormat()
}

/**
* @expectedException InvalidArgumentException
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Format "html" already registered, and override was set to "false".
*/
public function testRegisterFormatWithExistingFormat()
Expand All @@ -352,9 +356,18 @@ public function testNormalizePriorities($priorities, $expected)
public static function dataProviderForNormalizePriorities()
{
return array(
array(array('application/json', 'application/xml'), array('application/json', 'application/xml')),
array(array('json', 'application/xml', 'text/*', 'rdf', '*/*'), array('application/json', 'application/x-json', 'application/xml', 'text/*', 'application/rdf+xml', '*/*')),
array(array('json', 'html', '*/*'), array('application/json', 'application/x-json', 'text/html', 'application/xhtml+xml', '*/*')),
array(
array('application/json', 'application/xml'),
array('application/json', 'application/xml')
),
array(
array('json', 'application/xml', 'text/*', 'rdf', '*/*'),
array('application/json', 'application/x-json', 'application/xml', 'text/*', 'application/rdf+xml', '*/*')
),
array(
array('json', 'html', '*/*'),
array('application/json', 'application/x-json', 'text/html', 'application/xhtml+xml', '*/*')
),
);
}
}
43 changes: 41 additions & 2 deletions tests/Negotiation/Tests/LanguageNegotiatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

class LanguageNegotiatorTest extends TestCase
{

/**
* @var LanguageNegotiator
*/
private $negotiator;

protected function setUp()
Expand All @@ -22,7 +26,7 @@ protected function setUp()
public function testGetBestUsesQuality()
{
$acceptLanguageHeader = 'en; q=0.1, fr; q=0.4, fu; q=0.9, de; q=0.2';
$acceptHeader = $this->negotiator->getBest($acceptLanguageHeader);
$acceptHeader = $this->negotiator->getBest($acceptLanguageHeader);

$this->assertInstanceOf('Negotiation\AcceptHeader', $acceptHeader);
$this->assertEquals('fu', $acceptHeader->getValue());
Expand All @@ -37,7 +41,7 @@ public function testGetBestUsesQuality()
public function testGetBestIgnoresNonExistentContent()
{
$acceptLanguageHeader = 'en; q=0.1, fr; q=0.4, bu; q=1.0';
$acceptHeader = $this->negotiator->getBest($acceptLanguageHeader, array('en', 'fr'));
$acceptHeader = $this->negotiator->getBest($acceptLanguageHeader, array('en', 'fr'));

$this->assertInstanceOf('Negotiation\AcceptHeader', $acceptHeader);
$this->assertEquals('fr', $acceptHeader->getValue());
Expand All @@ -58,6 +62,41 @@ public function testGetBest($acceptLanguageHeader, $expected)
}
}

/**
* Given a accept header containing a generic language (here 'en')
* And priorities containing a localized version of that language
* Then the best language is mapped to 'en'
*/
public function testGenericLanguageAreMappedToSpecific()
{
$acceptLanguageHeader = 'fr-FR, en;q=0.8';
$priorities = array('en-US', 'de-DE');

$acceptHeader = $this->negotiator->getBest($acceptLanguageHeader, $priorities);

$this->assertInstanceOf('Negotiation\AcceptHeader', $acceptHeader);
$this->assertEquals('en-US', $acceptHeader->getValue());
}

public function testGetBestWithWildcard()
{
$acceptLanguageHeader = 'en, *;q=0.9';
$priorities = array('fr');

$acceptHeader = $this->negotiator->getBest($acceptLanguageHeader, $priorities);

$this->assertInstanceOf('Negotiation\AcceptHeader', $acceptHeader);
$this->assertEquals('fr', $acceptHeader->getValue());
}

public function testGetBestDoesNotMatchPriorities()
{
$acceptLanguageHeader = 'en, de';
$priorities = array('fr');

$this->assertNull($this->negotiator->getBest($acceptLanguageHeader, $priorities));
}

public static function dataProviderForGetBest()
{
return array(
Expand Down
21 changes: 15 additions & 6 deletions tests/Negotiation/Tests/NegotiatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
*/
class NegotiatorTest extends TestCase
{

/**
* @var Negotiator
*/
private $negotiator;

protected function setUp()
Expand All @@ -26,6 +30,11 @@ public function testGetBestReturnsNullWithEmptyHeader()
$this->assertNull($this->negotiator->getBest(''));
}

public function testGetBestReturnsNullWithUnmatchedHeader()
{
$this->assertNull($this->negotiator->getBest('foo, bar, yo', array('baz')));
}

public function testGetBestRespectsPriorities()
{
$acceptHeader = $this->negotiator->getBest('foo, bar, yo', array('yo'));
Expand All @@ -39,7 +48,7 @@ public function testGetBestInCaseInsensitive()
$acceptHeader = $this->negotiator->getBest('foo, bar, yo', array('YO'));

$this->assertInstanceOf('Negotiation\AcceptHeader', $acceptHeader);
$this->assertEquals('yo', $acceptHeader->getValue());
$this->assertEquals('YO', $acceptHeader->getValue());
}

public function testGetBestWithQualities()
Expand Down Expand Up @@ -105,7 +114,7 @@ public function testParseAcceptHeaderEnsuresPrecedence($header, $expected)

$i = 0;
foreach ($expected as $value => $quality) {
$this->assertEquals($value, $accepts[$i]->getValue());
$this->assertEquals($value, $accepts[$i]->getValue());
$this->assertEquals($quality, $accepts[$i]->getQuality());

$i++;
Expand Down Expand Up @@ -135,8 +144,8 @@ public static function dataProviderForTestParseAcceptHeader()
array("gzip, deflate\t,sdch", array('gzip', 'deflate', 'sdch')),
array('"this;should,not=matter"', array('"this;should,not=matter"')),
array('*;q=0.3,ISO-8859-1,utf-8;q=0.7', array('ISO-8859-1', 'utf-8', '*')),
array('*;q=0.3,ISO-8859-1;q=0.7,utf-8;q=0.7', array('ISO-8859-1', 'utf-8', '*')),
array('*;q=0.3,utf-8;q=0.7,ISO-8859-1;q=0.7', array('utf-8', 'ISO-8859-1', '*')),
array('*;q=0.3,ISO-8859-1;q=0.7,utf-8;q=0.7', array('ISO-8859-1', 'utf-8', '*')),
array('*;q=0.3,utf-8;q=0.7,ISO-8859-1;q=0.7', array('utf-8', 'ISO-8859-1', '*')),
);
}

Expand Down Expand Up @@ -168,7 +177,7 @@ public static function dataProviderForTestGetBest()
'iso-8859-1',
'shift-jis',
),
'ISO-8859-1'
'iso-8859-1'
),
array(
$pearCharsetHeader,
Expand Down Expand Up @@ -202,7 +211,7 @@ public static function dataProviderForTestGetBest()
'iso-8859-1',
'shift-jis',
),
'ISO-8859-1'
'iso-8859-1'
),
array(
$pearCharsetHeader2,
Expand Down

0 comments on commit 1749792

Please sign in to comment.