Page MenuHomeDevCentral

D2282.diff
No OneTemporary

D2282.diff

diff --git a/composer.json b/composer.json
--- a/composer.json
+++ b/composer.json
@@ -16,6 +16,7 @@
}
},
"require": {
+ "ext-intl": "*"
},
"require-dev": {
"nasqueron/codestyle": "^0.0.1",
diff --git a/src/Collections/OmniArray.php b/src/Collections/OmniArray.php
--- a/src/Collections/OmniArray.php
+++ b/src/Collections/OmniArray.php
@@ -3,6 +3,8 @@
namespace Keruald\OmniTools\Collections;
+use Keruald\OmniTools\Strings\Multibyte\OmniString;
+
class OmniArray {
/**
@@ -44,6 +46,16 @@
return $this;
}
+ public function map (callable $callable) : self {
+ $items = array_map($callable, $this->items);
+
+ return new self($items);
+ }
+
+ public function implode(string $delimiter) : OmniString {
+ return new OmniString(implode($delimiter, $this->items));
+ }
+
///
/// Getters methods
///
diff --git a/src/HTTP/URL.php b/src/HTTP/URL.php
new file mode 100644
--- /dev/null
+++ b/src/HTTP/URL.php
@@ -0,0 +1,191 @@
+<?php
+declare(strict_types=1);
+
+namespace Keruald\OmniTools\HTTP;
+
+use Keruald\OmniTools\Strings\Multibyte\OmniString;
+
+class URL {
+
+ ///
+ /// Constants
+ ///
+
+ /**
+ * Encode the query using RFC 3986, but keep / intact as a separators.
+ * As such, everything will be encoded excepted ~ - _ . / characters.
+ */
+ const ENCODE_RFC3986_SLASH_EXCEPTED = 1;
+
+ /**
+ * Encode the query using RFC 3986, including the /.
+ * As such, everything will be encoded excepted ~ - _ . characters.
+ */
+ const ENCODE_RFC3986_PURE = 2;
+
+ /**
+ * Consider the query already encoded.
+ */
+ const ENCODE_AS_IS = 3;
+
+ ///
+ /// Private members
+ ///
+
+ /**
+ * @var string
+ */
+ private $url;
+
+ /**
+ * @var int
+ */
+ private $queryEncoding;
+
+ ///
+ /// Constructors
+ ///
+
+ public function __construct ($url,
+ $queryEncoding = self::ENCODE_RFC3986_SLASH_EXCEPTED) {
+ $this->url = $url;
+ $this->queryEncoding = $queryEncoding;
+ }
+
+ public static function compose (string $protocol, string $domain,
+ string $query,
+ $queryEncoding = self::ENCODE_RFC3986_SLASH_EXCEPTED
+ ) : self {
+ return (new URL("", $queryEncoding))
+ ->update($protocol, $domain, $query);
+ }
+
+
+ ///
+ /// Getters and setters
+ ///
+
+ public function getProtocol () : string {
+ if (preg_match("@(.*?)://.*@", $this->url, $matches)) {
+ return $matches[1];
+ }
+
+ return "";
+ }
+
+ public function getDomain () : string {
+ if (preg_match("@://(.*?)/@", $this->url, $matches)) {
+ return self::beautifyDomain($matches[1]);
+ }
+
+ return "";
+ }
+
+ public function getQuery () : string {
+ if (preg_match("@(://.*?)?(/.*)@", $this->url, $matches)) {
+ return $this->beautifyQuery($matches[2]);
+ }
+
+ return "";
+ }
+
+ public function setProtocol ($protocol) : self {
+ $this->update($protocol, $this->getDomain(), $this->getQuery());
+
+ return $this;
+ }
+
+ public function setDomain ($domain) : self {
+ $this->update($this->getProtocol(), $domain, $this->getQuery());
+
+ return $this;
+ }
+
+ public function setQuery ($query,
+ $encodeMode = self::ENCODE_RFC3986_SLASH_EXCEPTED
+ ) : self {
+ $this->queryEncoding = $encodeMode;
+ $this->update($this->getProtocol(), $this->getDomain(), $query);
+
+ return $this;
+ }
+
+ private function isRootQuery($query) : bool {
+ return $this->queryEncoding !== self::ENCODE_RFC3986_PURE
+ && $query !== ""
+ && $query[0] === '/';
+ }
+
+ private function update (string $protocol, string $domain, string $query) : self {
+ $url = "";
+
+ if ($domain !== "") {
+ if ($protocol !== "") {
+ $url = $protocol;
+ }
+
+ $url .= "://" . self::normalizeDomain($domain);
+
+ if (!$this->isRootQuery($query)) {
+ $url .= "/";
+ }
+ }
+
+ $url .= $this->normalizeQuery($query);
+
+ $this->url = $url;
+
+ return $this;
+ }
+
+ public function normalizeQuery (string $query) : string {
+ switch ($this->queryEncoding) {
+ case self::ENCODE_RFC3986_SLASH_EXCEPTED:
+ return (new OmniString($query))
+ ->explode("/")
+ ->map("rawurlencode")
+ ->implode("/")
+ ->__toString();
+
+ case self::ENCODE_AS_IS:
+ return $query;
+
+ case self::ENCODE_RFC3986_PURE:
+ return rawurlencode($query);
+ }
+
+ throw new \Exception('Unexpected encoding value');
+ }
+
+ public function beautifyQuery (string $query) : string {
+ switch ($this->queryEncoding) {
+ case self::ENCODE_RFC3986_SLASH_EXCEPTED:
+ return (new OmniString($query))
+ ->explode("/")
+ ->map("rawurldecode")
+ ->implode("/")
+ ->__toString();
+
+ case self::ENCODE_AS_IS:
+ return $query;
+
+ case self::ENCODE_RFC3986_PURE:
+ return rawurldecode($query);
+ }
+
+ throw new \Exception('Unexpected encoding value');
+ }
+
+ public static function normalizeDomain (string $domain) : string {
+ return idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46);
+ }
+
+ public static function beautifyDomain (string $domain) : string {
+ return idn_to_utf8($domain, 0, INTL_IDNA_VARIANT_UTS46);
+ }
+
+ public function __toString () {
+ return $this->url;
+ }
+
+}
diff --git a/src/Strings/Multibyte/OmniString.php b/src/Strings/Multibyte/OmniString.php
--- a/src/Strings/Multibyte/OmniString.php
+++ b/src/Strings/Multibyte/OmniString.php
@@ -3,6 +3,8 @@
namespace Keruald\OmniTools\Strings\Multibyte;
+use Keruald\OmniTools\Collections\OmniArray;
+
class OmniString {
use WithEncoding;
@@ -85,6 +87,27 @@
return $bigrams;
}
+ ///
+ /// Transformation methods
+ ///
+
+ public function explode (string $delimiter,
+ int $limit = PHP_INT_MAX) : OmniArray {
+ if ($delimiter === "") {
+ if ($limit < 0) {
+ return new OmniArray;
+ }
+
+ return new OmniArray([$this->value]);
+ }
+
+ return new OmniArray(explode($delimiter, $this->value, $limit));
+ }
+
+ ///
+ /// Getters and setters
+ ///
+
/**
* @return string
*/
diff --git a/tests/Collections/OmniArrayTest.php b/tests/Collections/OmniArrayTest.php
new file mode 100644
--- /dev/null
+++ b/tests/Collections/OmniArrayTest.php
@@ -0,0 +1,35 @@
+<?php
+declare(strict_types=1);
+
+namespace Keruald\OmniTools\Tests\Collections;
+
+use Keruald\OmniTools\Collections\OmniArray;
+use PHPUnit\Framework\TestCase;
+
+class OmniArrayTest extends TestCase {
+
+ public function testMap () : void {
+ $actual = (new OmniArray([1, 2, 3, 4, 5]))
+ ->map(function ($x) { return $x * $x; })
+ ->toArray();
+
+ $this->assertEquals([1, 4, 9, 16, 25], $actual);
+ }
+
+ public function testImplode() : void {
+ $actual = (new OmniArray(["a", "b", "c"]))
+ ->implode(".")
+ ->__toString();
+
+ $this->assertEquals("a.b.c", $actual);
+ }
+
+ public function testImplodeWithoutDelimiter() : void {
+ $actual = (new OmniArray(["a", "b", "c"]))
+ ->implode("")
+ ->__toString();
+
+ $this->assertEquals("abc", $actual);
+ }
+
+}
diff --git a/tests/HTTP/URLTest.php b/tests/HTTP/URLTest.php
new file mode 100644
--- /dev/null
+++ b/tests/HTTP/URLTest.php
@@ -0,0 +1,84 @@
+<?php
+declare(strict_types=1);
+
+namespace Keruald\OmniTools\Tests\HTTP;
+
+use Keruald\OmniTools\HTTP\URL;
+use PHPUnit\Framework\TestCase;
+
+class URLTest extends TestCase {
+
+ /**
+ * @dataProvider provideURLsAndComponents
+ */
+ public function testGetDomain ($url, $expectedDomain) : void {
+ $url = new URL($url);
+
+ $this->assertEquals($expectedDomain, $url->getDomain());
+ }
+
+ /**
+ * @dataProvider provideURLsAndComponents
+ */
+ public function testGetProtocol ($url, $_, $expectedProtocol) : void {
+ $url = new URL($url);
+
+ $this->assertEquals($expectedProtocol, $url->getProtocol());
+ }
+
+ /**
+ * @dataProvider provideURLsAndComponents
+ */
+ public function testGetQuery ($url, $_, $__, $expectedQuery) : void {
+ $url = new URL($url);
+
+ $this->assertEquals($expectedQuery, $url->getQuery());
+ }
+
+ public function testSetProtocol () : void {
+ $url = new URL("https://acme.tld/foo");
+ $url->setProtocol("xizzy");
+
+ $this->assertEquals("xizzy", $url->getProtocol());
+ }
+
+ public function testSetDomain () : void {
+ $url = new URL("https://acme.tld/foo");
+ $url->setDomain("xizzy");
+
+ $this->assertEquals("xizzy", $url->getDomain());
+ }
+
+ public function testSetQuery () : void {
+ $url = new URL("https://acme.tld/foo");
+ $url->setQuery("/xizzy");
+
+ $this->assertEquals("/xizzy", $url->getQuery());
+ }
+
+ public function testSetQueryWithSlashForgotten () : void {
+ $url = new URL("https://acme.tld/foo");
+ $url->setQuery("xizzy");
+
+ $this->assertEquals("/xizzy", $url->getQuery());
+ }
+
+ /**
+ * @dataProvider provideURLsAndComponents
+ */
+ public function testCompose ($expectedUrl, $domain, $protocol, $query) {
+ $this->assertEquals(
+ $expectedUrl,
+ URL::compose($protocol, $domain, $query)->__toString()
+ );
+ }
+
+ public function provideURLsAndComponents () : iterable {
+ yield ["http://foo/bar", "foo", "http", "/bar"];
+ yield ["https://xn--dghrefn-mxa.nasqueron.org/", "dæghrefn.nasqueron.org", "https", "/"];
+ yield ["://foo/bar", "foo", "", "/bar"];
+ yield ["/bar", "", "", "/bar"];
+ yield ["http://foo/bar%20quux", "foo", "http", "/bar quux"];
+ }
+
+}
diff --git a/tests/Strings/Multibyte/OmniStringTest.php b/tests/Strings/Multibyte/OmniStringTest.php
--- a/tests/Strings/Multibyte/OmniStringTest.php
+++ b/tests/Strings/Multibyte/OmniStringTest.php
@@ -67,6 +67,17 @@
$this->assertEquals($expectedBigrams, $actualBigrams);
}
+ /**
+ * @dataProvider provideExplosions
+ */
+ public function testExplode (string $delimiter, string $imploded, array $exploded) : void {
+ $actual = (new OmniString($imploded))
+ ->explode($delimiter)
+ ->toArray();
+
+ $this->assertEquals($exploded, $actual);
+ }
+
///
/// Data providers
///
@@ -93,5 +104,14 @@
yield ["", []];
}
+ public function provideExplosions () : iterable {
+ yield ["/", "a/b/c", ['a', 'b', 'c']];
+ yield ["/", "abc", ['abc']];
+ yield ["/", "/b/c", ['', 'b', 'c']];
+ yield ["/", "a/b/", ['a', 'b', '']];
+
+ yield ["", "a/b/c", ['a/b/c']];
+ yield ["x", "a/b/c", ['a/b/c']];
+ }
}

File Metadata

Mime Type
text/plain
Expires
Mon, Nov 18, 01:53 (21 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2250088
Default Alt Text
D2282.diff (11 KB)

Event Timeline