Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"xp-forge/web": "^3.0 | ^2.9",
"xp-forge/compression": "^1.0",
"xp-forge/json": "^5.0 | ^4.0",
"xp-forge/marshalling": "^2.0",
"php": ">=7.0.0"
},
"require-dev" : {
Expand Down
11 changes: 6 additions & 5 deletions src/main/php/web/frontend/Delegate.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,30 +47,31 @@ public function name() {
* Returns a map of named sources to read arguments from request. Lazily
* initialized on first use.
*
* @return [:(function(web.Request, string): var)]
* @return [:var]
*/
public function parameters() {
if (null === $this->parameters) {
$this->parameters= [];
foreach ($this->method->parameters() as $param) {
$type= $param->constraint()->type();

// Check for parameter annotations...
foreach ($param->annotations() as $annotation) {
$source= self::$SOURCES[$annotation->name()] ?? self::$SOURCES['default'];
$name= $annotation->argument(0) ?? $param->name();

if ($param->optional()) {
$this->parameters[$name]= function($req, $name) use($source, $param) {
$this->parameters[$name]= [$type, function($req, $name) use($source, $param) {
return $source($req, $name) ?? $param->default();
};
}];
} else {
$this->parameters[$name]= $source;
$this->parameters[$name]= [$type, $source];
}
continue 2;
}

// ...falling back to selecting the parameter from the segments
$this->parameters[$param->name()]= self::$SOURCES['segment'];
$this->parameters[$param->name()]= [$type, self::$SOURCES['segment']];
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/main/php/web/frontend/Frontend.class.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php namespace web\frontend;

use lang\reflection\TargetException;
use util\data\Marshalling;
use web\{Error, Handler, Request};

/**
Expand Down Expand Up @@ -92,10 +93,11 @@ private function view($req, $res, $delegate, $matches= []) {
return $this->errors()->handle(new Error(403, 'Incorrect CSRF token for '.$delegate->name()));
}

$marshalling= new Marshalling();
try {
$args= [];
foreach ($delegate->parameters() as $name => $source) {
$args[]= $matches[$name] ?? $source($req, $name);
foreach ($delegate->parameters() as $name => $spec) {
$args[]= $marshalling->unmarshal($matches[$name] ?? $spec[1]($req, $name), $spec[0]);
}

return $delegate->invoke($args);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public function patterns_sorted_by_length() {
'#get/users/(?<id>[^/]+)/avatar$#',
'#delete/users/(?<id>[^/]+)$#',
'#get/users/(?<id>[^/]+)$#',
'#get/post/(?<id>[^/]+)$#',
'#get/blogs/stats$#',
'#get/blogs/?$#',
'#post/users$#',
Expand Down
14 changes: 13 additions & 1 deletion src/test/php/web/frontend/unittest/HandlingTest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use lang\IndexOutOfBoundsException;
use test\Assert;
use test\{Expect, Test, TestCase, Values};
use web\frontend\unittest\actions\{Blogs, Home, Select, Users};
use web\frontend\unittest\actions\{Blogs, Home, Select, Users, Posts};
use web\frontend\{Frontend, Templates, View};
use web\io\{TestInput, TestOutput};
use web\{Error, Request, Response};
Expand Down Expand Up @@ -408,4 +408,16 @@ public function head_request_does_not_send_response() {
$res= $this->handle($fixture, 'HEAD', '/users/1');
Assert::equals("\r\n\r\n", strstr($res->output()->bytes(), "\r\n\r\n"));
}

#[Test]
public function marshals_to_custom_input() {
$fixture= new Frontend(new Posts(), newinstance(Templates::class, [], [
'write' => function($template, $context, $out) use(&$result) {
$result= $context;
}
]));

$this->handle($fixture, 'GET', '/post/1234');
$this->assertContext(['id' => '1234', 'request' => ['params' => []]], $result);
}
}
12 changes: 12 additions & 0 deletions src/test/php/web/frontend/unittest/ObjectId.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php namespace web\frontend\unittest;

class ObjectId {
private $id;

public function __construct($id) {
$this->id= (string)$id;
}


public function string() { return $this->id; }
}
13 changes: 13 additions & 0 deletions src/test/php/web/frontend/unittest/actions/Posts.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php namespace web\frontend\unittest\actions;

use web\frontend\unittest\ObjectId;
use web\frontend\{Handler, Get};

#[Handler('/post')]
class Posts {

#[Get('/{id}')]
public function get(ObjectId $id) {
return ['id' => $id->string()];
}
}