Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AcceptLanguageLocale class #1

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 4 additions & 23 deletions src/AcceptLanguage.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
*/
class AcceptLanguage
{
/** @throws \BadMethodCallException */
private function __construct() { throw new \BadMethodCallException(); }

/**
* @param string $http_accept_language
* @return array
Expand Down Expand Up @@ -115,7 +118,7 @@ public static function parse($locale_str)
$locale['language'] = '*';
}

return array($q, self::fillLocaleArrayKey($locale));
return array($q, new AcceptLanguageLocale($locale));
}

/**
Expand All @@ -131,26 +134,4 @@ private static function sort_tags(array $a, array $b)

return ($a[0] < $b[0]) ? -1 : 1;
}

/**
* @param array $locale
* @return array
* @link http://php.net/manual/locale.composelocale.php
*/
private static function fillLocaleArrayKey(array $locale)
{
static $empty_locale = [
'language' => '',
'script' => '',
'region' => '',
'variant1' => '',
'variant2' => '',
'variant3' => '',
'private1' => '',
'private2' => '',
'private3' => '',
];

return $locale + $empty_locale;
}
}
103 changes: 103 additions & 0 deletions src/AcceptLanguageLocale.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php
namespace Teto\HTTP;
use Locale;

/**
* HTTP `Accept-Language` locale object
*
* @package Teto\HTTP*
* @copyright Copyright (c) 2014 USAMI Kenta
* @author USAMI Kenta <[email protected]>
* @license MIT License
*
* @property-read string $language
* @property-read string $script
* @property-read string $region
* @property-read string $variant1
* @property-read string $variant2
* @property-read string $variant3
* @property-read string $private1
* @property-read string $private2
* @property-read string $private3
*/
class AcceptLanguageLocale implements \ArrayAccess, \IteratorAggregate
{
private $locale = [
'language' => '',
'script' => '',
'region' => '',
'variant1' => '',
'variant2' => '',
'variant3' => '',
'private1' => '',
'private2' => '',
'private3' => '',
];

/**
* @param array $locale
* @link http://php.net/manual/locale.composelocale.php
*/
public function __construct(array $locale)
{
foreach ($locale as $l => $v) {
$this->locale[$l] = $v;
}
}

/**
* @return array
*/
public function getAsArray()
{
return $this->locale;
}

/**
* @return \ArrayIterator
*/
public function getIterator()
{
return new \ArrayIterator($this->locale);
}

/**
* @throws \OutOfRangeException
*/
public function __get($name)
{
if (!array_key_exists($name, $this->locale)) {
throw new \OutOfRangeException($name);
}

return $this->locale[$name];
}

public function __isset($name)
{
return isset($this->locale[$name]);
}

/**
* @throws \OutOfBoundsException
*/
public function offsetGet($name)
{
if (!array_key_exists($name, $this->locale)) {
throw new \OutOfBoundsException($name);
}

return $this->locale[$name];
}

public function offsetExists($offset)
{
return isset($this->locale[$offset]);
}

// AcceptLanguage class is immutable.
public function __set($_name, $_value) { throw new \LogicException; }
public function __unset($_name) { throw new \LogicException; }
public function offsetSet($_offset, $_value) { throw new \LogicException; }
public function offsetUnset($_offset) { throw new \LogicException; }
}
80 changes: 80 additions & 0 deletions tests/AcceptLanguageLocaleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php
namespace Teto\HTTP;

/**
* HTTP `Accept-Language` header parser
*
* @package Teto\HTTP*
* @copyright Copyright (c) 2014 USAMI Kenta
* @author USAMI Kenta <[email protected]>
* @license MIT License
*/
class AcceptLanguage_ObjectTest extends TestCase
{
public static $empty_locale = [
'language' => '',
'script' => '',
'region' => '',
'variant1' => '',
'variant2' => '',
'variant3' => '',
'private1' => '',
'private2' => '',
'private3' => '',
];

public function test()
{
$actual = new AcceptLanguageLocale([]);

$this->assertSame(self::$empty_locale, $actual->getAsArray());
foreach (self::$empty_locale as $l => $v) {
$this->assertSame($v, $actual[$l]);
$this->assertSame($v, $actual->$l);
$this->assertTrue(isset($actual[$l]));
$this->assertTrue(empty($actual[$l]));
$this->assertTrue(isset($actual->$l));
$this->assertTrue(empty($actual->$l));
}

foreach ($actual as $a => $b) {
$this->assertSame(self::$empty_locale[$a], $b);
}
}

/**
* @expectedException \LogicException
*/
public function test_set()
{
$actual = new AcceptLanguageLocale([]);
$actual->error = '/(^o^)\';
}

/**
* @expectedException \LogicException
*/
public function test_unset()
{
$actual = new AcceptLanguageLocale([]);
unset($actual->error);
}

/**
* @expectedException \LogicException
*/
public function test_offsetSet()
{
$actual = new AcceptLanguageLocale([]);
$actual['error'] = '/(^o^)\';
}

/**
* @expectedException \LogicException
*/
public function test_offsetUnset()
{
$actual = new AcceptLanguageLocale([]);
unset($actual['error']);
}
}
40 changes: 20 additions & 20 deletions tests/AcceptLanguageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,40 +41,40 @@ public function dataProviderFor_getLanguage()
['ja',
'expected' => [
100 => [
['language' => 'ja'] + $e,
new AcceptLanguageLocale(['language' => 'ja'] + $e),
],
],
],
['ja-Hrkt-JPN;q=0.111111',
'expected' => [
11 => [
['language' => 'ja', 'script' => 'Hrkt', 'region' => 'JP'] + $e,
new AcceptLanguageLocale(['language' => 'ja', 'script' => 'Hrkt', 'region' => 'JP'] + $e),
],
],
],
['ja;q=0.9, en-GB',
'expected' => [
100 => [
['language' => 'en', 'region' => 'GB'] + $e
new AcceptLanguageLocale(['language' => 'en', 'region' => 'GB'] + $e),
],
90 => [
['language' => 'ja'] + $e
new AcceptLanguageLocale(['language' => 'ja'] + $e),
],
],
],
['ja-Kata;q=0.1,en_PCN;q=0.8,zh_HKG;q=0.9,tlh-Latn-US',
'expected' => [
100 => [
['language' => 'tlh', 'script' => 'Latn', 'region' => 'US'] + $e
new AcceptLanguageLocale(['language' => 'tlh', 'script' => 'Latn', 'region' => 'US'] + $e),
],
90 => [
['language' => 'zh', 'region' => 'HK'] + $e
new AcceptLanguageLocale(['language' => 'zh', 'region' => 'HK'] + $e),
],
80 => [
['language' => 'en', 'region' => 'PN'] + $e
new AcceptLanguageLocale(['language' => 'en', 'region' => 'PN'] + $e),
],
10 => [
['language' => 'ja', 'script' => 'Kata'] + $e
new AcceptLanguageLocale(['language' => 'ja', 'script' => 'Kata'] + $e),
],
],
],
Expand All @@ -96,17 +96,17 @@ public function dataProviderFor_parse()
$e = self::$empty_locale;

return [
['ja', 'expected' => [1.0, ['language' => 'ja'] + $e]],
['ja-JP', 'expected' => [1.0, ['language' => 'ja', 'region' => 'JP'] + $e]],
['ja-Hira', 'expected' => [1.0, ['language' => 'ja', 'script' => 'Hira'] + $e]],
['ja;q=1.0', 'expected' => [1.0, ['language' => 'ja'] + $e]],
['ja; q=1.0', 'expected' => [1.0, ['language' => 'ja'] + $e]],
['ja-JP;q=1', 'expected' => [1.0, ['language' => 'ja', 'region' => 'JP'] + $e]],
['ja;q=1.00', 'expected' => [1.0, ['language' => 'ja'] + $e]],
['*', 'expected' => [1.0, ['language' => '*'] + $e]],
['*-Hant;q=0.1', 'expected' => [0.1, ['language' => '*', 'script' => 'Hant'] + $e]],
['zh-*-TW', 'expected' => [1.0, ['language' => 'zh', 'region' => 'TW'] + $e]],
['xx', 'expected' => [1.0, ['language' => 'xx'] + $e]],
['ja', [1.0, new AcceptLanguageLocale(['language' => 'ja'] + $e)]],
['ja-JP', [1.0, new AcceptLanguageLocale(['language' => 'ja', 'region' => 'JP'] + $e)]],
['ja-Hira', [1.0, new AcceptLanguageLocale(['language' => 'ja', 'script' => 'Hira'] + $e)]],
['ja;q=1.0', [1.0, new AcceptLanguageLocale(['language' => 'ja'] + $e)]],
['ja; q=1.0', [1.0, new AcceptLanguageLocale(['language' => 'ja'] + $e)]],
['ja-JP;q=1', [1.0, new AcceptLanguageLocale(['language' => 'ja', 'region' => 'JP'] + $e)]],
['ja;q=1.00', [1.0, new AcceptLanguageLocale(['language' => 'ja'] + $e)]],
['*', [1.0, new AcceptLanguageLocale(['language' => '*'] + $e)]],
['*-Hant;q=0.1', [0.1, new AcceptLanguageLocale(['language' => '*', 'script' => 'Hant'] + $e)]],
['zh-*-TW', [1.0, new AcceptLanguageLocale(['language' => 'zh', 'region' => 'TW'] + $e)]],
['xx', [1.0, new AcceptLanguageLocale(['language' => 'xx'] + $e)]],
];
}

Expand All @@ -116,7 +116,7 @@ public function dataProviderFor_parse()
public function test_detect($accept_language, $default, $expected)
{
$known_languages = ['ja', 'en', 'es', 'ko'];
$strategy = function (array $locale) use ($known_languages) {
$strategy = function (AcceptLanguageLocale $locale) use ($known_languages) {
$is_wildcard = isset($locale['language']) && $locale['language'] === '*';
if (empty($locale['language']) && !$is_wildcard) {
return null;
Expand Down