Page MenuHomeDevCentral

No OneTemporary

diff --git a/composer.json b/composer.json
index fc4c281..d1a7e58 100644
--- a/composer.json
+++ b/composer.json
@@ -1,26 +1,27 @@
{
"name": "keruald/omnitools",
"description": "Utilities classes",
"type": "library",
"license": "BSD-2-Clause",
"authors": [
{
"name": "Sébastien Santoro",
"email": "dereckson@espace-win.org"
}
],
"autoload": {
"psr-4": {
"Keruald\\OmniTools\\": "src/",
"Keruald\\OmniTools\\Tests\\": "tests/"
}
},
"require": {
+ "ext-intl": "*"
},
"require-dev": {
"nasqueron/codestyle": "^0.0.1",
"phan/phan": "^2.4",
"phpunit/phpunit": "^7.5",
"squizlabs/php_codesniffer": "^3.5"
}
}
diff --git a/src/Collections/OmniArray.php b/src/Collections/OmniArray.php
index df9a597..30a60c1 100644
--- a/src/Collections/OmniArray.php
+++ b/src/Collections/OmniArray.php
@@ -1,55 +1,67 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Collections;
+use Keruald\OmniTools\Strings\Multibyte\OmniString;
+
class OmniArray {
/**
* @var array
*/
private $items = [];
///
/// Constructors
///
public function __construct (?iterable $items) {
if ($items === null) {
return;
}
if (is_array($items)) {
$this->items = $items;
return;
}
foreach ($items as $item) {
$this->items[] = $item;
}
}
public static function explode (string $delimiter, string $string, int $limit = PHP_INT_MAX) : self {
return new OmniArray(explode($delimiter, $string, $limit));
}
///
/// Transformation methods
///
public function toIntegers () : self {
array_walk($this->items, ArrayUtilities::toIntegerCallback());
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
///
public function toArray () : array {
return $this->items;
}
}
diff --git a/src/HTTP/URL.php b/src/HTTP/URL.php
new file mode 100644
index 0000000..67dc3f1
--- /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
index c62550b..d18c780 100644
--- a/src/Strings/Multibyte/OmniString.php
+++ b/src/Strings/Multibyte/OmniString.php
@@ -1,102 +1,125 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Strings\Multibyte;
+use Keruald\OmniTools\Collections\OmniArray;
+
class OmniString {
use WithEncoding;
///
/// Private members
///
/**
* @var string
*/
private $value;
///
/// Constructor
///
public function __construct (string $value = '', string $encoding = '') {
$this->value = $value;
$this->setEncoding($encoding ?: "UTF-8");
}
///
/// Magic methods
///
public function __toString() : string {
return $this->value;
}
///
/// Helper methods
///
public function pad(
int $padLength = 0,
string $padString = ' ',
int $padType = STR_PAD_RIGHT
) : string {
return (new StringPad)
->setInput($this->value)
->setEncoding($this->encoding)
->setPadLength($padLength)
->setPadString($padString)
->setPadType($padType)
->pad();
}
public function startsWith (string $start) : bool {
return StringUtilities::startsWith($this->value, $start);
}
public function endsWith (string $end) : bool {
return StringUtilities::endsWith($this->value, $end);
}
public function len () : int {
return mb_strlen($this->value, $this->encoding);
}
public function getChars () : array {
$chars = [];
$len = $this->len();
for ($i = 0 ; $i < $len ; $i++) {
$chars[] = mb_substr($this->value, $i, 1, $this->encoding);
}
return $chars;
}
public function getBigrams () {
$bigrams = [];
$len = $this->len();
for ($i = 0 ; $i < $len - 1 ; $i++) {
$bigrams[] = mb_substr($this->value, $i, 2, $this->encoding);
}
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
*/
public function getValue () : string {
return $this->value;
}
/**
* @param string $value
*/
public function setValue (string $value) {
$this->value = $value;
}
}
diff --git a/tests/Collections/OmniArrayTest.php b/tests/Collections/OmniArrayTest.php
new file mode 100644
index 0000000..473a78c
--- /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
index 0000000..1c43e15
--- /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
index 0df1e87..5005ef3 100644
--- a/tests/Strings/Multibyte/OmniStringTest.php
+++ b/tests/Strings/Multibyte/OmniStringTest.php
@@ -1,97 +1,117 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Tests\Strings\Multibyte;
use Keruald\OmniTools\Strings\Multibyte\OmniString;
use PHPUnit\Framework\TestCase;
class OmniStringTest extends TestCase {
/**
* @var OmniString
*/
private $string;
protected function setUp () : void {
$this->string = new OmniString("foo");
}
public function testToString () : void {
$this->assertEquals("foo", (string)$this->string);
$this->assertEquals("foo", $this->string->__toString());
}
public function testPad () : void {
$paddedString = $this->string->pad(9, '-=-', STR_PAD_BOTH);
$this->assertEquals("-=-foo-=-", $paddedString);
}
public function testStartsWith () : void {
$this->assertTrue($this->string->startsWith("fo"));
$this->assertTrue($this->string->startsWith(""));
$this->assertTrue($this->string->startsWith("foo"));
$this->assertFalse($this->string->startsWith("Fo"));
$this->assertFalse($this->string->startsWith("bar"));
}
public function testEndsWith () : void {
$this->assertTrue($this->string->endsWith("oo"));
$this->assertTrue($this->string->endsWith(""));
$this->assertTrue($this->string->endsWith("foo"));
$this->assertFalse($this->string->endsWith("oO"));
$this->assertFalse($this->string->endsWith("bar"));
}
public function testLen () : void {
$this->assertEquals(3, $this->string->len());
}
/**
* @dataProvider provideCharactersArrays
*/
public function testGetChars (string $string, array $expectedCharacters) : void {
$actualCharacters = (new OmniString($string))->getChars();
$this->assertEquals($expectedCharacters, $actualCharacters);
}
/**
* @dataProvider provideCharactersBigrams
*/
public function testBigrams (string $string, array $expectedBigrams) : void {
$actualBigrams = (new OmniString($string))->getBigrams();
$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
///
public function provideCharactersArrays () : iterable {
yield ["foo", ['f', 'o', 'o']];
yield [
'àèòàFOOàèòà',
['à', 'è', 'ò', 'à', 'F', 'O', 'O', 'à', 'è', 'ò', 'à']
];
yield ["🇩🇪", ["🇩", "🇪"]];
yield ["", []];
}
public function provideCharactersBigrams () : iterable {
yield ["foo", ['fo', 'oo']];
yield ["night", ['ni', 'ig', 'gh', 'ht']];
yield ["🇩🇪", ["🇩🇪"]];
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/x-diff
Expires
Mon, Nov 25, 19:11 (8 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2260817
Default Alt Text
(17 KB)

Event Timeline