Skip to content

Commit

Permalink
feat: Implement keyGet() and keyGet2() built-in method, fix #97 (#103)
Browse files Browse the repository at this point in the history
  • Loading branch information
basakest committed Sep 9, 2021
1 parent c414268 commit 132167b
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/Model/FunctionMap.php
Expand Up @@ -41,9 +41,15 @@ public static function loadFunctionMap(): self
$fm->addFunction('keyMatch', function (...$args) {
return BuiltinOperations::keyMatchFunc(...$args);
});
$fm->addFunction('keyGet', function (...$args) {
return BuiltinOperations::keyGetFunc(...$args);
});
$fm->addFunction('keyMatch2', function (...$args) {
return BuiltinOperations::keyMatch2Func(...$args);
});
$fm->addFunction('keyGet2', function (...$args) {
return BuiltinOperations::keyGet2Func(...$args);
});
$fm->addFunction('regexMatch', function (...$args) {
return BuiltinOperations::regexMatchFunc(...$args);
});
Expand Down
93 changes: 93 additions & 0 deletions src/Util/BuiltinOperations.php
Expand Up @@ -52,6 +52,43 @@ public static function keyMatchFunc(...$args): bool
return self::keyMatch($name1, $name2);
}

/**
* KeyGet returns the matched part
* For example, "/foo/bar/foo" matches "/foo/*"
* "bar/foo" will been returned
*
* @param string $key1
* @param string $key2
* @return string
*/
public static function keyGet(string $key1, string $key2): string
{
$i = strpos($key2, '*');
if ($i === false) {
return "";
}
if (strlen($key1) > $i) {
if (substr($key1, 0, $i) == substr($key2, 0, $i)) {
return substr($key1, $i);
}
}
return '';
}

/**
* KeyGetFunc is the wrapper for KeyGet
*
* @param mixed ...$args
* @return string
*/
public static function keyGetFunc(...$args)
{
$name1 = $args[0];
$name2 = $args[1];

return self::keyGet($name1, $name2);
}

/**
* Determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
* For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/:resource".
Expand Down Expand Up @@ -96,6 +133,62 @@ public static function keyMatch2Func(...$args): bool
return self::keyMatch2($name1, $name2);
}

/**
* KeyGet2 returns value matched pattern
* For example, "/resource1" matches "/:resource"
* if the pathVar == "resource", then "resource1" will be returned
*
* @param string $key1
* @param string $key2
* @param string $pathVar
* @return string
*/
public static function keyGet2(string $key1, string $key2, string $pathVar): string
{
$key2 = str_replace(['/*'], ['/.*'], $key2);

$pattern = '/:[^\/]+/';
$keys = [];
preg_match_all($pattern, $key2, $keys);
$keys = $keys[0];
$key2 = preg_replace_callback(
$pattern,
function ($m) {
return '([^\/]+)';
},
$key2
);

$key2 = "~^" . $key2 . "$~";
$values = [];
preg_match($key2, $key1, $values);

if (count($values) === 0) {
return '';
}
foreach ($keys as $i => $key) {
if ($pathVar == substr($key, 1)) {
return $values[$i + 1];
}
}
return '';
}

/**
* KeyGet2Func is the wrapper for KeyGet2
*
* @param mixed ...$args
* @return string
*/
public static function keyGet2Func(...$args)
{
$name1 = $args[0];
$name2 = $args[1];
$key = $args[2];

return self::keyGet2($name1, $name2, $key);
}

/**
* Determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
* For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/{resource}".
Expand Down
57 changes: 57 additions & 0 deletions tests/Unit/Util/BuiltinOperationsTest.php
Expand Up @@ -37,6 +37,16 @@ private function globMatchFunc($name1, $name2)
return BuiltinOperations::globMatchFunc($name1, $name2);
}

public function keyGetFunc($name1, $name2)
{
return BuiltinOperations::KeyGetFunc($name1, $name2);
}

public function keyGet2Func($name1, $name2, $pathVar)
{
return BuiltinOperations::KeyGet2Func($name1, $name2, $pathVar);
}

public function testKeyMatchFunc()
{
$this->assertTrue($this->keyMatchFunc('/foo', '/foo'));
Expand Down Expand Up @@ -136,4 +146,51 @@ public function testGlobMatchFunc()

$this->assertTrue($this->globMatchFunc('/foo/bar', '/foo/*'));
}

public function testKeyGetFunc()
{
$this->assertEquals('', $this->keyGetFunc('/foo', '/foo'));
$this->assertEquals('', $this->keyGetFunc('/foo', '/foo*'));
$this->assertEquals('', $this->keyGetFunc('/foo', '/foo/*'));
$this->assertEquals('', $this->keyGetFunc('/foo/bar', '/foo'));
$this->assertEquals('/bar', $this->keyGetFunc('/foo/bar', '/foo*'));
$this->assertEquals('bar', $this->keyGetFunc('/foo/bar', '/foo/*'));
$this->assertEquals('', $this->keyGetFunc('/foobar', '/foo'));
$this->assertEquals('bar', $this->keyGetFunc('/foobar', '/foo*'));
$this->assertEquals('', $this->keyGetFunc('/foobar', '/foo/*'));
}

public function testKeyGet2Func()
{
$this->assertEquals('', $this->keyGet2Func("/foo", "/foo", "id"));
$this->assertEquals('', $this->keyGet2Func("/foo", "/foo*", "id"));
$this->assertEquals('', $this->keyGet2Func("/foo", "/foo/*", "id"));
$this->assertEquals('', $this->keyGet2Func("/foo/bar", "/foo", "id"));
// different with KeyMatch.
$this->assertEquals('', $this->keyGet2Func("/foo/bar", "/foo*", "id"));
$this->assertEquals('', $this->keyGet2Func("/foo/bar", "/foo/*", "id"));
$this->assertEquals('', $this->keyGet2Func("/foobar", "/foo", "id"));
// different with KeyMatch.
$this->assertEquals('', $this->keyGet2Func("/foobar", "/foo*", "id"));
$this->assertEquals('', $this->keyGet2Func("/foobar", "/foo/*", "id"));
$this->assertEquals('', $this->keyGet2Func("/", "/:resource", "resource"));
$this->assertEquals('resource1', $this->keyGet2Func("/resource1", "/:resource", "resource"));
$this->assertEquals('', $this->keyGet2Func("/myid", "/:id/using/:resId", "id"));
$this->assertEquals('myid', $this->keyGet2Func("/myid/using/myresid", "/:id/using/:resId", "id"));
$this->assertEquals('myresid', $this->keyGet2Func("/myid/using/myresid", "/:id/using/:resId", "resId"));

$this->assertEquals('', $this->keyGet2Func("/proxy/myid", "/proxy/:id/*", "id"));
$this->assertEquals('myid', $this->keyGet2Func("/proxy/myid/", "/proxy/:id/*", "id"));
$this->assertEquals('myid', $this->keyGet2Func("/proxy/myid/res", "/proxy/:id/*", "id"));
$this->assertEquals('myid', $this->keyGet2Func("/proxy/myid/res/res2", "/proxy/:id/*", "id"));
$this->assertEquals('myid', $this->keyGet2Func("/proxy/myid/res/res2/res3", "/proxy/:id/*", "id"));
$this->assertEquals('myid', $this->keyGet2Func("/proxy/myid/res/res2/res3", "/proxy/:id/res/*", "id"));
$this->assertEquals('', $this->keyGet2Func('/proxy/', "/proxy/:id/*", "id"));
$this->assertEquals('alice', $this->keyGet2Func("/alice", "/:id", "id"));
$this->assertEquals('alice', $this->keyGet2Func("/alice/all", "/:id/all", "id"));
$this->assertEquals('', $this->keyGet2Func("/alice", "/:id/all", "id"));
$this->assertEquals('', $this->keyGet2Func("/alice/all", "/:id", "id"));

$this->assertEquals('', $this->keyGet2Func("/alice/all", "/:/all", ""));
}
}

0 comments on commit 132167b

Please sign in to comment.