Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F11723016
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
14 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/Collections/WeightedList.php b/src/Collections/WeightedList.php
index 4060c22..ca8d5ef 100644
--- a/src/Collections/WeightedList.php
+++ b/src/Collections/WeightedList.php
@@ -1,75 +1,103 @@
<?php
namespace Keruald\OmniTools\Collections;
use ArrayIterator;
use Countable;
use Iterator;
use IteratorAggregate;
class WeightedList implements IteratorAggregate, Countable {
/**
* @var WeightedValue[]
*/
private $list;
public function __construct () {
$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
///
public function add ($item, float $weight = 1.0) : void {
$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 = [];
}
public function getHeaviest () {
$value = null;
foreach ($this->list as $candidate) {
if ($value === null || $candidate->compareTo($value) > 0) {
$value = $candidate;
}
}
return $value;
}
public function toSortedArray () : array {
$weights = [];
$values = [];
foreach ($this->list as $item) {
$weights[] = $item->getWeight();
$values[] = $item->getValue();
}
array_multisort($weights, SORT_DESC, $values, SORT_ASC);
return $values;
}
///
/// IteratorAggregate implementation
///
public function getIterator () : Iterator {
return new ArrayIterator($this->list);
}
///
/// Countable implementation
///
public function count () : int {
return count($this->list);
}
}
diff --git a/src/Collections/WeightedValue.php b/src/Collections/WeightedValue.php
index 921a523..a86555a 100644
--- a/src/Collections/WeightedValue.php
+++ b/src/Collections/WeightedValue.php
@@ -1,75 +1,85 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Collections;
use TypeError;
class WeightedValue implements Comparable {
///
/// Constants
///
const DEFAULT_WEIGHT = 1.0;
///
/// Private members
///
/**
* @var float
*/
private $weight = self::DEFAULT_WEIGHT;
/**
* @var mixed
*/
private $value;
///
- /// Constructor
+ /// Constructors
///
public function __construct ($value, float $weight = self::DEFAULT_WEIGHT) {
$this->value = $value;
$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
///
public function getWeight () : float {
return $this->weight;
}
public function setWeight (float $weight) : self {
$this->weight = $weight;
return $this;
}
public function getValue () {
return $this->value;
}
public function setValue ($value) : self {
$this->value = $value;
return $this;
}
///
/// Helper methods
///
public function compareTo (object $other) : int {
if (!$other instanceof WeightedValue) {
throw new TypeError;
}
return $this->getWeight() <=> $other->getWeight();
}
}
diff --git a/src/HTTP/Requests/AcceptedLanguages.php b/src/HTTP/Requests/AcceptedLanguages.php
new file mode 100644
index 0000000..4cf3222
--- /dev/null
+++ b/src/HTTP/Requests/AcceptedLanguages.php
@@ -0,0 +1,40 @@
+<?php
+declare(strict_types=1);
+
+namespace Keruald\OmniTools\HTTP\Requests;
+
+use Keruald\OmniTools\Collections\WeightedList;
+
+class AcceptedLanguages {
+
+ /**
+ * @var string
+ */
+ private $acceptedLanguages;
+
+ ///
+ /// Constructor
+ ///
+
+ public function __construct (string $acceptedLanguages = '') {
+ $this->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
index 2d8c2b3..aea7a9d 100644
--- a/src/HTTP/Requests/Request.php
+++ b/src/HTTP/Requests/Request.php
@@ -1,10 +1,11 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\HTTP\Requests;
class Request {
+ use WithAcceptedLanguages;
use WithRemoteAddress;
}
diff --git a/src/HTTP/Requests/WithAcceptedLanguages.php b/src/HTTP/Requests/WithAcceptedLanguages.php
new file mode 100644
index 0000000..a23a3d4
--- /dev/null
+++ b/src/HTTP/Requests/WithAcceptedLanguages.php
@@ -0,0 +1,22 @@
+<?php
+declare(strict_types=1);
+
+
+namespace Keruald\OmniTools\HTTP\Requests;
+
+
+trait WithAcceptedLanguages {
+
+ /**
+ * Gets the languages accepted by the browser, by order of priority.
+ *
+ * This will read the HTTP_ACCEPT_LANGUAGE variable sent by the browser in the
+ * HTTP request.
+ *
+ * @return string[] each item a language accepted by browser
+ */
+ public static function getAcceptedLanguages () : array {
+ return AcceptedLanguages::fromServer()->getLanguageCodes();
+ }
+
+}
diff --git a/tests/Collections/WeightedListTest.php b/tests/Collections/WeightedListTest.php
index e3daeb9..f600887 100644
--- a/tests/Collections/WeightedListTest.php
+++ b/tests/Collections/WeightedListTest.php
@@ -1,79 +1,87 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Tests\Collections;
use Keruald\OmniTools\Collections\WeightedValue;
use Keruald\OmniTools\Collections\WeightedList;
use PHPUnit\Framework\TestCase;
class WeightedListTest extends TestCase {
/**
* @var WeightedList
*/
private $list;
///
/// Fixtures
///
protected function setUp () : void {
$this->list = new WeightedList;
$this->list->add("LOW", 0.1);
$this->list->add("HIGH", 4);
$this->list->add("AVERAGE");
}
///
/// Tests
///
public function testAdd () : void {
$count = count($this->list);
$this->list->add("ANOTHER");
$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));
}
public function testGetHeaviest () : void {
$this->assertEquals(4, $this->list->getHeaviest()->getWeight());
}
public function testToSortedArray () : void {
$array = $this->list->toSortedArray();
$this->assertEquals(3, count($array));
$this->assertEquals(["HIGH", "AVERAGE", "LOW"], $array);
}
public function testToSortedArrayWithDuplicateValues () : void {
$this->list->add("AVERAGE");
$array = $this->list->toSortedArray();
$this->assertEquals(4, count($array));
$this->assertEquals(["HIGH", "AVERAGE", "AVERAGE", "LOW"], $array);
}
public function testGetIterator () : void {
$count = 0;
foreach ($this->list as $item) {
$this->assertInstanceOf(WeightedValue::class, $item);
$count++;
}
$this->assertEquals(3, $count);
}
public function testCount() : void {
$this->assertEquals(3, $this->list->count());
}
}
diff --git a/tests/Collections/WeightedValueTest.php b/tests/Collections/WeightedValueTest.php
index f26be5a..e56747d 100644
--- a/tests/Collections/WeightedValueTest.php
+++ b/tests/Collections/WeightedValueTest.php
@@ -1,79 +1,101 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Tests\Collections;
use Keruald\OmniTools\Collections\WeightedValue;
use PHPUnit\Framework\TestCase;
class WeightedValueTest extends TestCase {
/**
* @var WeightedValue
*/
private $lowValue;
/**
* @var WeightedValue
*/
private $highValue;
///
/// Fixtures
///
protected function setUp () : void {
$this->lowValue = new WeightedValue("LOW", 0.1);
$this->highValue = new WeightedValue("HIGH");
}
///
/// Tests
///
public function testGetWeight () : void {
$this->assertSame(0.1, $this->lowValue->getWeight());
$this->assertSame(
WeightedValue::DEFAULT_WEIGHT,
$this->highValue->getWeight()
);
}
public function testSetWeight () : void {
$this->lowValue->setWeight(0.2);
$this->assertSame(0.2, $this->lowValue->getWeight());
}
public function testGetValue () : void {
$this->assertEquals("LOW", $this->lowValue->getValue());
$this->assertEquals("HIGH", $this->highValue->getValue());
}
public function testSetValue () : void {
$this->lowValue->setValue("FOO");
$this->assertEquals("FOO", $this->lowValue->getValue());
}
public function testCompareTo () : void {
$this->assertEquals(
0,
$this->lowValue->compareTo($this->lowValue)
);
$this->assertEquals(
-1,
$this->lowValue->compareTo($this->highValue)
);
$this->assertEquals(
1,
$this->highValue->compareTo($this->lowValue)
);
}
public function testCompareToWithApplesAndPears () : void {
$this->expectException("TypeError");
$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
index 0000000..d210050
--- /dev/null
+++ b/tests/HTTP/Requests/AcceptedLanguagesTest.php
@@ -0,0 +1,47 @@
+<?php
+declare(strict_types=1);
+
+namespace Keruald\OmniTools\Tests\HTTP\Requests;
+
+use Keruald\OmniTools\HTTP\Requests\AcceptedLanguages;
+use PHPUnit\Framework\TestCase;
+
+class AcceptedLanguagesTest extends TestCase {
+
+ /**
+ * @var AcceptedLanguages
+ */
+ private $languages;
+
+ protected function setUp () : void {
+ $this->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
index 6b721a1..f55338e 100644
--- a/tests/HTTP/Requests/RequestTest.php
+++ b/tests/HTTP/Requests/RequestTest.php
@@ -1,33 +1,48 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Tests\HTTP\Requests;
use Keruald\OmniTools\HTTP\Requests\Request;
use PHPUnit\Framework\TestCase;
class RequestTest extends TestCase {
/**
* @covers \Keruald\OmniTools\HTTP\Requests\Request::getRemoteAddress
* @backupGlobals enabled
*/
public function testGetRemoteAddress () : void {
$this->assertEmpty(Request::getRemoteAddress());
$_SERVER = [
'REMOTE_ADDR' => '10.0.0.2',
];
$this->assertEquals('10.0.0.2', Request::getRemoteAddress());
$_SERVER += [
'HTTP_X_FORWARDED_FOR' => '10.0.0.3',
'HTTP_CLIENT_IP' => '10.0.0.4',
];
$this->assertEquals(
'10.0.0.3', Request::getRemoteAddress(),
"HTTP_X_FORWARDED_FOR must be prioritized."
);
}
+ /**
+ * @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()
+ );
+ }
+
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Sep 18, 07:25 (9 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2990174
Default Alt Text
(14 KB)
Attached To
Mode
rKERUALD Keruald libraries development repository
Attached
Detach File
Event Timeline
Log In to Comment