diff --git a/src/Collections/WeightedList.php b/src/Collections/WeightedList.php --- a/src/Collections/WeightedList.php +++ b/src/Collections/WeightedList.php @@ -18,6 +18,26 @@ $this->list = []; } + /** + * @param string $expression A string like "a,b;q=0.1,c;q=0.4" + * + * @return WeightedList + * + * @see RFC 7231, section 5.3.1 + */ + public static function parse (string $expression) : WeightedList { + $list = new WeightedList(); + + if ($expression !== "") { + $items = explode(',', $expression); + foreach ($items as $item) { + $list->addFromString($item); + } + } + + return $list; + } + /// /// Helper methods /// @@ -26,6 +46,14 @@ $this->list[] = new WeightedValue($item, $weight); } + public function addWeightedValue (WeightedValue $value) : void { + $this->list[] = $value; + } + + public function addFromString (string $expression) : void { + $this->addWeightedValue(WeightedValue::parse($expression)); + } + public function clear () : void { $this->list = []; } diff --git a/src/Collections/WeightedValue.php b/src/Collections/WeightedValue.php --- a/src/Collections/WeightedValue.php +++ b/src/Collections/WeightedValue.php @@ -28,7 +28,7 @@ private $value; /// - /// Constructor + /// Constructors /// public function __construct ($value, float $weight = self::DEFAULT_WEIGHT) { @@ -36,6 +36,16 @@ $this->weight = $weight; } + public static function parse (string $expression) : WeightedValue { + $pair = explode(';q=', $expression); + + if (count($pair) == 1) { + return new WeightedValue($pair[0]); + } + + return new WeightedValue($pair[0], (float)$pair[1]); + } + /// /// Getters and setters /// diff --git a/src/HTTP/Requests/AcceptedLanguages.php b/src/HTTP/Requests/AcceptedLanguages.php new file mode 100644 --- /dev/null +++ b/src/HTTP/Requests/AcceptedLanguages.php @@ -0,0 +1,40 @@ +acceptedLanguages = $acceptedLanguages; + } + + public static function fromServer () : self { + return new self(self::extractFromHeaders()); + } + + /// + /// Helper methods to determine the languages + /// + + public static function extractFromHeaders () : string { + return $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? ""; + } + + public function getLanguageCodes () : array { + return WeightedList::parse($this->acceptedLanguages) + ->toSortedArray(); + } + +} diff --git a/src/HTTP/Requests/Request.php b/src/HTTP/Requests/Request.php --- a/src/HTTP/Requests/Request.php +++ b/src/HTTP/Requests/Request.php @@ -5,6 +5,7 @@ class Request { + use WithAcceptedLanguages; use WithRemoteAddress; } diff --git a/src/HTTP/Requests/WithAcceptedLanguages.php b/src/HTTP/Requests/WithAcceptedLanguages.php new file mode 100644 --- /dev/null +++ b/src/HTTP/Requests/WithAcceptedLanguages.php @@ -0,0 +1,22 @@ +getLanguageCodes(); + } + +} diff --git a/tests/Collections/WeightedListTest.php b/tests/Collections/WeightedListTest.php --- a/tests/Collections/WeightedListTest.php +++ b/tests/Collections/WeightedListTest.php @@ -37,6 +37,14 @@ $this->assertEquals($count + 1, count($this->list)); } + public function testAddWeightedValue () : void { + $count = count($this->list); + + $this->list->addWeightedValue(new WeightedValue("ANOTHER")); + + $this->assertEquals($count + 1, count($this->list)); + } + public function testClear () : void { $this->list->clear(); $this->assertEquals(0, count($this->list)); diff --git a/tests/Collections/WeightedValueTest.php b/tests/Collections/WeightedValueTest.php --- a/tests/Collections/WeightedValueTest.php +++ b/tests/Collections/WeightedValueTest.php @@ -76,4 +76,26 @@ $this->highValue->compareTo(new \stdClass); } + /** + * @dataProvider provideExpressionstoParse + */ + public function testParse ($expression, $expectedValue, $expectedWeight) : void { + $value = WeightedValue::Parse($expression); + + $this->assertEquals($expectedValue, $value->getValue()); + $this->assertEquals($expectedWeight, $value->getWeight()); + } + + /// + /// Data providers + /// + + public function provideExpressionstoParse () : iterable { + yield ["", "", 1.0]; + yield ["de", "de", 1.0]; + yield ["de;q=1.0", "de", 1.0]; + yield ["de;q=0.7", "de", 0.7]; + yield [";;q=0.7", ";", 0.7]; + } + } diff --git a/tests/HTTP/Requests/AcceptedLanguagesTest.php b/tests/HTTP/Requests/AcceptedLanguagesTest.php new file mode 100644 --- /dev/null +++ b/tests/HTTP/Requests/AcceptedLanguagesTest.php @@ -0,0 +1,47 @@ +languages = new AcceptedLanguages("en-US,en;q=0.9,fr;q=0.8"); + } + + public function testExtractFromHeaders () : void { + $this->assertEquals("", AcceptedLanguages::extractFromHeaders()); + + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = "de"; + $this->assertEquals("de", AcceptedLanguages::extractFromHeaders()); + } + + public function testFromServer () : void { + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = "de"; + $languages = AcceptedLanguages::fromServer(); + + $this->assertEquals(["de"], $languages->getLanguageCodes()); + } + + public function testGetLanguageCodes () : void { + $this->assertEquals( + ["en-US", "en", "fr"], + $this->languages->getLanguageCodes() + ); + } + + public function testGetLanguageCodesWithBlankInformation () : void { + $languages = new AcceptedLanguages; + + $this->assertEquals([], $languages->getLanguageCodes()); + } + +} diff --git a/tests/HTTP/Requests/RequestTest.php b/tests/HTTP/Requests/RequestTest.php --- a/tests/HTTP/Requests/RequestTest.php +++ b/tests/HTTP/Requests/RequestTest.php @@ -30,4 +30,19 @@ ); } + /** + * @covers \Keruald\OmniTools\HTTP\Requests\Request::getAcceptedLanguages + * @backupGlobals enabled + */ + public function testGetAcceptedLanguages () : void { + $_SERVER = [ + 'HTTP_ACCEPT_LANGUAGE' => 'fr,en-US;q=0.7,en;q=0.3', + ]; + + $this->assertEquals( + ["fr", "en-US", "en"], + Request::getAcceptedLanguages() + ); + } + }