Skip to content

Commit 21c490e

Browse files
author
Ian Barber
committed
Support level 4 of URI template RFC
Add support for the explode and strlen parameters in the spec. This has made the combine function slightly unpleasant.
1 parent b062426 commit 21c490e

2 files changed

Lines changed: 132 additions & 12 deletions

File tree

src/Google/Utils/URITemplate.php

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -134,25 +134,63 @@ private function replaceVars(
134134
) {
135135
if (strpos($section, ",") === false) {
136136
// If we only have a single value, we can immediately process.
137-
return $this->combine($section, $parameters, $combine, $reserved, $tag_empty);
137+
return $this->combine($section, $parameters, $sep, $combine, $reserved, $tag_empty);
138138
} else {
139139
// If we have multiple values, we need to split and loop over them.
140140
// Each is treated individually, then glued together with the
141141
// separator character.
142142
$vars = explode(",", $section);
143-
$ret = array();
144-
foreach ($vars as $var) {
145-
$ret[] = $this->combine($var, $parameters, $combine, $reserved, $tag_empty);
146-
}
147-
return implode($sep, $ret);
143+
return $this->combineList($vars, $sep, $parameters, $combine, $reserved, $tag_empty);
148144
}
149145
}
150-
151-
public function combine($key, $parameters, $combine, $reserved, $tag_empty)
146+
147+
public function combine($key, $parameters, $sep, $combine, $reserved, $tag_empty)
152148
{
149+
$length = false;
150+
$explode = false;
151+
$skip_final_combine = false;
152+
153+
if (strpos($key, ":") !== false) {
154+
list($key, $length) = explode(":", $key);
155+
}
156+
157+
if ($key[strlen($key) - 1] == "*") {
158+
$explode = true;
159+
$key = substr($key, 0, -1);
160+
}
161+
153162
if (!empty($parameters[$key])) {
154-
// For an individual value, we need to URL encode the data.
155-
$value = rawurlencode($parameters[$key]);
163+
if (is_array($parameters[$key])) {
164+
$values = array();
165+
$use_keys = false;
166+
if (!is_numeric(key($parameters[$key]))) {
167+
$use_keys = true;
168+
}
169+
foreach ($parameters[$key] as $pkey => $pvalue) {
170+
$pvalue = $this->getValue($pvalue, $length);
171+
if ($use_keys) {
172+
if ($explode) {
173+
$skip_final_combine = true;
174+
$values[] = $pkey . "=" . $pvalue; // Explode triggers = combine.
175+
} else {
176+
$values[] = $pkey;
177+
$values[] = $pvalue;
178+
}
179+
} else {
180+
if ($combine && $explode) {
181+
$skip_final_combine = true;
182+
$values[$pkey] = $key . $combine . $pvalue;
183+
} else {
184+
$values[$pkey] = $pvalue;
185+
}
186+
}
187+
}
188+
$list_sep = $explode ? $sep : ",";
189+
$value = implode($list_sep, $values);
190+
} else {
191+
// For an individual value, we need to URL encode the data.
192+
$value = $this->getValue($parameters[$key], $length);
193+
}
156194
} else if ($tag_empty) {
157195
// If we are just indicating empty values with their key name, return that.
158196
return $key;
@@ -165,10 +203,28 @@ public function combine($key, $parameters, $combine, $reserved, $tag_empty)
165203
}
166204
// If we do not need to include the key name, we just return the raw
167205
// value.
168-
if (!$combine) {
206+
if (!$combine || $skip_final_combine) {
169207
return $value;
170208
}
171209
// Else we combine the key name: foo=bar
172210
return $key . $combine . $value;
173211
}
212+
213+
private function combineList($vars, $sep, $parameters, $combine, $reserved, $tag_empty)
214+
{
215+
$ret = array();
216+
foreach ($vars as $var) {
217+
$ret[] = $this->combine($var, $parameters, $sep, $combine, $reserved, $tag_empty);
218+
}
219+
return implode($sep, $ret);
220+
}
221+
222+
private function getValue($value, $length)
223+
{
224+
if ($length) {
225+
$value = substr($value, 0, $length);
226+
}
227+
$value = rawurlencode($value);
228+
return $value;
229+
}
174230
}

tests/general/URITemplateTest.php

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public function testLevelTwo() {
3737
$var = "value";
3838
$hello = "Hello World!";
3939
$path = "/foo/bar";
40-
40+
4141
$urit = new Google_Utils_URITemplate();
4242
$this->assertEquals("value",
4343
$urit->parse("{+var}", array("var" => $var)));
@@ -108,6 +108,70 @@ public function testLevelThree() {
108108
$urit->parse("{&x,y,empty}", array("x" => $x, "y" => $y, "empty" => $empty)));
109109
}
110110

111+
public function testLevelFour() {
112+
$values = array(
113+
'var' => "value",
114+
'hello' => "Hello World!",
115+
'path' => "/foo/bar",
116+
'list' => array("red", "green", "blue"),
117+
'keys' => array("semi" => ";", "dot" => ".", "comma" => ","),
118+
);
119+
120+
$tests = array(
121+
"{var:3}" => "val",
122+
"{var:30}" => "value",
123+
"{list}" => "red,green,blue",
124+
"{list*}" => "red,green,blue",
125+
"{keys}" => "semi,%3B,dot,.,comma,%2C",
126+
"{keys*}" => "semi=%3B,dot=.,comma=%2C",
127+
"{+path:6}/here" => "/foo/b/here",
128+
"{+list}" => "red,green,blue",
129+
"{+list*}" => "red,green,blue",
130+
"{+keys}" => "semi,;,dot,.,comma,,",
131+
"{+keys*}" => "semi=;,dot=.,comma=,",
132+
"{#path:6}/here" => "#/foo/b/here",
133+
"{#list}" => "#red,green,blue",
134+
"{#list*}" => "#red,green,blue",
135+
"{#keys}" => "#semi,;,dot,.,comma,,",
136+
"{#keys*}" => "#semi=;,dot=.,comma=,",
137+
"X{.var:3}" => "X.val",
138+
"X{.list}" => "X.red,green,blue",
139+
"X{.list*}" => "X.red.green.blue",
140+
"X{.keys}" => "X.semi,%3B,dot,.,comma,%2C",
141+
"X{.keys*}" => "X.semi=%3B.dot=..comma=%2C",
142+
"{/var:1,var}" => "/v/value",
143+
"{/list}" => "/red,green,blue",
144+
"{/list*}" => "/red/green/blue",
145+
"{/list*,path:4}" => "/red/green/blue/%2Ffoo",
146+
"{/keys}" => "/semi,%3B,dot,.,comma,%2C",
147+
"{/keys*}" => "/semi=%3B/dot=./comma=%2C",
148+
"{;hello:5}" => ";hello=Hello",
149+
"{;list}" => ";list=red,green,blue",
150+
"{;list*}" => ";list=red;list=green;list=blue",
151+
"{;keys}" => ";keys=semi,%3B,dot,.,comma,%2C",
152+
"{;keys*}" => ";semi=%3B;dot=.;comma=%2C",
153+
"{?var:3}" => "?var=val",
154+
"{?list}" => "?list=red,green,blue",
155+
"{?list*}" => "?list=red&list=green&list=blue",
156+
"{?keys}" => "?keys=semi,%3B,dot,.,comma,%2C",
157+
"{?keys*}" => "?semi=%3B&dot=.&comma=%2C",
158+
"{&var:3}" => "&var=val",
159+
"{&list}" => "&list=red,green,blue",
160+
"{&list*}" => "&list=red&list=green&list=blue",
161+
"{&keys}" => "&keys=semi,%3B,dot,.,comma,%2C",
162+
"{&keys*}" => "&semi=%3B&dot=.&comma=%2C",
163+
"find{?list*}" => "find?list=red&list=green&list=blue",
164+
"www{.list*}" => "www.red.green.blue"
165+
166+
);
167+
168+
$urit = new Google_Utils_URITemplate();
169+
170+
foreach($tests as $input => $output) {
171+
$this->assertEquals($output, $urit->parse($input, $values), $input . " failed");
172+
}
173+
}
174+
111175
public function testMultipleAnnotations() {
112176
$var = "value";
113177
$hello = "Hello World!";

0 commit comments

Comments
 (0)